[{"data":1,"prerenderedAt":5657},["ShallowReactive",2],{"article_list_vue_":3},[4,3520,4273,5050],{"_path":5,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":9,"description":10,"excerpt":10,"tags":11,"image":15,"publishDate":16,"body":17,"_type":3511,"_id":3512,"_source":3513,"_file":3514,"_stem":3515,"_extension":3516,"author":3517},"/ckeefer/2024-7/vpubsub","2024-7",false,"","Vue 3 Pub / Sub: All aboard the (event) bus","We like Vue at A+L. We think it's one of the best frontend frameworks, and a great choice pretty much anywhere you might otherwise be tempted to use React.",[12,13,14],"js","vue","pub/sub","/ckeefer/2024-7/img/event_bus.png","2024-08-15",{"type":18,"children":19,"toc":3495},"root",[20,45,50,57,79,84,99,104,134,139,144,149,163,169,192,199,583,589,610,928,934,954,1072,1078,1091,1466,1485,1491,1496,1502,1515,1600,1613,1753,1758,1897,1902,1938,1965,1970,2823,2872,2877,2890,3407,3413,3456,3462,3467,3489],{"type":21,"tag":22,"props":23,"children":24},"element","p",{},[25,28,35,37,43],{"type":26,"value":27},"text","We ",{"type":21,"tag":29,"props":30,"children":32},"a",{"href":31},"/search/user:ckeefer/why/vue",[33],{"type":26,"value":34},"like Vue at A+L",{"type":26,"value":36},". We think it's ",{"type":21,"tag":29,"props":38,"children":40},{"href":39},"/search/user:phendry/frontend/frameworks/in/2024",[41],{"type":26,"value":42},"one of the best frontend frameworks",{"type":26,"value":44},", and a great choice pretty much anywhere you might otherwise be tempted to use React.",{"type":21,"tag":22,"props":46,"children":47},{},[48],{"type":26,"value":49},"That said, it's not going to solve every need out of the box. Its robust ecosystem is actually one of its strongest points; chances are that a decent option (or more than one) exists to satisfy a variety of common needs. Let's talk today about our own contribution to this flourishing ecosystem, and why you'd want to use it.",{"type":21,"tag":51,"props":52,"children":54},"h3",{"id":53},"hit-that-subscribe-button",[55],{"type":26,"value":56},"Hit That Subscribe Button",{"type":21,"tag":22,"props":58,"children":59},{},[60,62,69,71,77],{"type":26,"value":61},"In Vue, you've probably run into cases where you need one component to know about some event, or gain access to some bit of data, that's sequestered off in another component. If they were in relationship with one another - parent -> child, or grandparent -> parent -> child, etc., you could ",{"type":21,"tag":63,"props":64,"children":66},"code",{"className":65},[],[67],{"type":26,"value":68},"$emit",{"type":26,"value":70}," an event; and you can send data back down the other way through ",{"type":21,"tag":63,"props":72,"children":74},{"className":73},[],[75],{"type":26,"value":76},"props",{"type":26,"value":78}," (although this can sometimes be a little awkward). Crossing from one unrelated component to another, though, is a problem Vue isn't going to directly help you with.",{"type":21,"tag":22,"props":80,"children":81},{},[82],{"type":26,"value":83},"We don't want to couple our disparate components though, by directly sharing data or having one call the other - that's nasty design that limits their flexibility and reusability.",{"type":21,"tag":22,"props":85,"children":86},{},[87,89,97],{"type":26,"value":88},"One way we can solve this conundrum is with data stores, like vuex or ",{"type":21,"tag":29,"props":90,"children":94},{"href":91,"rel":92},"https://pinia.vuejs.org/",[93],"nofollow",[95],{"type":26,"value":96},"pinia",{"type":26,"value":98}," - we've been using the latter to good effect. There's an upcoming article there - but this isn't that one.",{"type":21,"tag":22,"props":100,"children":101},{},[102],{"type":26,"value":103},"In this one, let's talk about another way we can communicate between disparate components: the event bus, or rather it's older cousin, the Publish / Subscribe pattern.",{"type":21,"tag":22,"props":105,"children":106},{},[107,109,116,118,124,126,132],{"type":26,"value":108},"The ",{"type":21,"tag":29,"props":110,"children":113},{"href":111,"rel":112},"https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern",[93],[114],{"type":26,"value":115},"Publish/Subscribe pattern",{"type":26,"value":117}," allows you to ",{"type":21,"tag":63,"props":119,"children":121},{"className":120},[],[122],{"type":26,"value":123},"subscribe",{"type":26,"value":125}," to messages of interest, and ",{"type":21,"tag":63,"props":127,"children":129},{"className":128},[],[130],{"type":26,"value":131},"publish",{"type":26,"value":133}," those same messages from elsewhere within your application - your subscribers then receive these messages (via callback functions).",{"type":21,"tag":22,"props":135,"children":136},{},[137],{"type":26,"value":138},"If you're not familiar with this pattern, it's a very flexible form of event handling. It allows communications between different components or services while keeping them decoupled - the publisher of an event never needs to know the identity of any potential subscribers, and vice-versa.",{"type":21,"tag":22,"props":140,"children":141},{},[142],{"type":26,"value":143},"Keeping components of your application from being tightly coupled is generally good design, but you'll need to consider whether it's appropriate and helpful in your particular use-case - no tool is always the right tool, not every problem is a nail in want of a hammer. Pub/sub can become a problem in a complex application where events are coming in hot-and-heavy, because it can be difficult to track down just where any given event is coming from.",{"type":21,"tag":22,"props":145,"children":146},{},[147],{"type":26,"value":148},"You should be careful in making events easily referenceable (e.g. don't use a bare string as your key, have a central place where all event names are visible and importable from), and opt for single-hops as often as possible (e.g. avoid having an event publication trigger a subscriber to publish another event which causes a subscriber to publish another event, etc. - instead, have a single publication trigger subscribers, without allowing the subscribers to publish their own events in turn).",{"type":21,"tag":22,"props":150,"children":151},{},[152,154,161],{"type":26,"value":153},"If you know pub/sub is what you need, or you're considering it, you may want to check out our plugin, ",{"type":21,"tag":29,"props":155,"children":158},{"href":156,"rel":157},"https://www.npmjs.com/package/vpubsub",[93],[159],{"type":26,"value":160},"VPubSub",{"type":26,"value":162},". You can use it with or without Vue; and if you use it with Vue, it does a little extra magic to make your life easier. Let's dive in.",{"type":21,"tag":51,"props":164,"children":166},{"id":165},"how-does-it-work",[167],{"type":26,"value":168},"How Does It Work?",{"type":21,"tag":22,"props":170,"children":171},{},[172,174,181,183,190],{"type":26,"value":173},"Let's look at some common and uncommon use-cases, both in general, and then including Vue - both with the ",{"type":21,"tag":29,"props":175,"children":178},{"href":176,"rel":177},"https://vuejs.org/api/#options-api",[93],[179],{"type":26,"value":180},"Options API",{"type":26,"value":182},", and the ",{"type":21,"tag":29,"props":184,"children":187},{"href":185,"rel":186},"https://vuejs.org/api/#composition-api",[93],[188],{"type":26,"value":189},"Composition API",{"type":26,"value":191},":",{"type":21,"tag":193,"props":194,"children":196},"h4",{"id":195},"subscribe-to-a-single-event",[197],{"type":26,"value":198},"Subscribe to a single event",{"type":21,"tag":200,"props":201,"children":204},"pre",{"className":202,"code":203,"language":12,"meta":8,"style":8},"language-js shiki shiki-themes github-light github-dark","import {vent} from \"vpubsub\";\n\nconst EVENTS = {\n    PLAYER:{\n        START:'start.player',\n        END:'end.player',\n    }\n};\n\nvent.on(EVENTS.PLAYER.START, (arg1, arg2, ...rst) => {\n    // Do something useful with the event and arguments.\n    // The arguments will be whatever was passed during the call to `trigger`.\n});\n\n// ... elsewhere in your application ...\nvent.trigger(EVENTS.PLAYER.START, 'event', 'args', 40, 'or', 'as', 'many as you like',)\n",[205],{"type":21,"tag":63,"props":206,"children":207},{"__ignoreMap":8},[208,242,252,277,286,305,323,332,341,349,442,452,461,470,478,487],{"type":21,"tag":209,"props":210,"children":213},"span",{"class":211,"line":212},"line",1,[214,220,226,231,237],{"type":21,"tag":209,"props":215,"children":217},{"style":216},"--shiki-default:#D73A49;--shiki-dark:#F97583",[218],{"type":26,"value":219},"import",{"type":21,"tag":209,"props":221,"children":223},{"style":222},"--shiki-default:#24292E;--shiki-dark:#E1E4E8",[224],{"type":26,"value":225}," {vent} ",{"type":21,"tag":209,"props":227,"children":228},{"style":216},[229],{"type":26,"value":230},"from",{"type":21,"tag":209,"props":232,"children":234},{"style":233},"--shiki-default:#032F62;--shiki-dark:#9ECBFF",[235],{"type":26,"value":236}," \"vpubsub\"",{"type":21,"tag":209,"props":238,"children":239},{"style":222},[240],{"type":26,"value":241},";\n",{"type":21,"tag":209,"props":243,"children":245},{"class":211,"line":244},2,[246],{"type":21,"tag":209,"props":247,"children":249},{"emptyLinePlaceholder":248},true,[250],{"type":26,"value":251},"\n",{"type":21,"tag":209,"props":253,"children":255},{"class":211,"line":254},3,[256,261,267,272],{"type":21,"tag":209,"props":257,"children":258},{"style":216},[259],{"type":26,"value":260},"const",{"type":21,"tag":209,"props":262,"children":264},{"style":263},"--shiki-default:#005CC5;--shiki-dark:#79B8FF",[265],{"type":26,"value":266}," EVENTS",{"type":21,"tag":209,"props":268,"children":269},{"style":216},[270],{"type":26,"value":271}," =",{"type":21,"tag":209,"props":273,"children":274},{"style":222},[275],{"type":26,"value":276}," {\n",{"type":21,"tag":209,"props":278,"children":280},{"class":211,"line":279},4,[281],{"type":21,"tag":209,"props":282,"children":283},{"style":222},[284],{"type":26,"value":285},"    PLAYER:{\n",{"type":21,"tag":209,"props":287,"children":289},{"class":211,"line":288},5,[290,295,300],{"type":21,"tag":209,"props":291,"children":292},{"style":222},[293],{"type":26,"value":294},"        START:",{"type":21,"tag":209,"props":296,"children":297},{"style":233},[298],{"type":26,"value":299},"'start.player'",{"type":21,"tag":209,"props":301,"children":302},{"style":222},[303],{"type":26,"value":304},",\n",{"type":21,"tag":209,"props":306,"children":308},{"class":211,"line":307},6,[309,314,319],{"type":21,"tag":209,"props":310,"children":311},{"style":222},[312],{"type":26,"value":313},"        END:",{"type":21,"tag":209,"props":315,"children":316},{"style":233},[317],{"type":26,"value":318},"'end.player'",{"type":21,"tag":209,"props":320,"children":321},{"style":222},[322],{"type":26,"value":304},{"type":21,"tag":209,"props":324,"children":326},{"class":211,"line":325},7,[327],{"type":21,"tag":209,"props":328,"children":329},{"style":222},[330],{"type":26,"value":331},"    }\n",{"type":21,"tag":209,"props":333,"children":335},{"class":211,"line":334},8,[336],{"type":21,"tag":209,"props":337,"children":338},{"style":222},[339],{"type":26,"value":340},"};\n",{"type":21,"tag":209,"props":342,"children":344},{"class":211,"line":343},9,[345],{"type":21,"tag":209,"props":346,"children":347},{"emptyLinePlaceholder":248},[348],{"type":26,"value":251},{"type":21,"tag":209,"props":350,"children":352},{"class":211,"line":351},10,[353,358,364,369,374,379,384,388,393,398,404,409,414,418,423,428,433,438],{"type":21,"tag":209,"props":354,"children":355},{"style":222},[356],{"type":26,"value":357},"vent.",{"type":21,"tag":209,"props":359,"children":361},{"style":360},"--shiki-default:#6F42C1;--shiki-dark:#B392F0",[362],{"type":26,"value":363},"on",{"type":21,"tag":209,"props":365,"children":366},{"style":222},[367],{"type":26,"value":368},"(",{"type":21,"tag":209,"props":370,"children":371},{"style":263},[372],{"type":26,"value":373},"EVENTS",{"type":21,"tag":209,"props":375,"children":376},{"style":222},[377],{"type":26,"value":378},".",{"type":21,"tag":209,"props":380,"children":381},{"style":263},[382],{"type":26,"value":383},"PLAYER",{"type":21,"tag":209,"props":385,"children":386},{"style":222},[387],{"type":26,"value":378},{"type":21,"tag":209,"props":389,"children":390},{"style":263},[391],{"type":26,"value":392},"START",{"type":21,"tag":209,"props":394,"children":395},{"style":222},[396],{"type":26,"value":397},", (",{"type":21,"tag":209,"props":399,"children":401},{"style":400},"--shiki-default:#E36209;--shiki-dark:#FFAB70",[402],{"type":26,"value":403},"arg1",{"type":21,"tag":209,"props":405,"children":406},{"style":222},[407],{"type":26,"value":408},", ",{"type":21,"tag":209,"props":410,"children":411},{"style":400},[412],{"type":26,"value":413},"arg2",{"type":21,"tag":209,"props":415,"children":416},{"style":222},[417],{"type":26,"value":408},{"type":21,"tag":209,"props":419,"children":420},{"style":216},[421],{"type":26,"value":422},"...",{"type":21,"tag":209,"props":424,"children":425},{"style":400},[426],{"type":26,"value":427},"rst",{"type":21,"tag":209,"props":429,"children":430},{"style":222},[431],{"type":26,"value":432},") ",{"type":21,"tag":209,"props":434,"children":435},{"style":216},[436],{"type":26,"value":437},"=>",{"type":21,"tag":209,"props":439,"children":440},{"style":222},[441],{"type":26,"value":276},{"type":21,"tag":209,"props":443,"children":445},{"class":211,"line":444},11,[446],{"type":21,"tag":209,"props":447,"children":449},{"style":448},"--shiki-default:#6A737D;--shiki-dark:#6A737D",[450],{"type":26,"value":451},"    // Do something useful with the event and arguments.\n",{"type":21,"tag":209,"props":453,"children":455},{"class":211,"line":454},12,[456],{"type":21,"tag":209,"props":457,"children":458},{"style":448},[459],{"type":26,"value":460},"    // The arguments will be whatever was passed during the call to `trigger`.\n",{"type":21,"tag":209,"props":462,"children":464},{"class":211,"line":463},13,[465],{"type":21,"tag":209,"props":466,"children":467},{"style":222},[468],{"type":26,"value":469},"});\n",{"type":21,"tag":209,"props":471,"children":473},{"class":211,"line":472},14,[474],{"type":21,"tag":209,"props":475,"children":476},{"emptyLinePlaceholder":248},[477],{"type":26,"value":251},{"type":21,"tag":209,"props":479,"children":481},{"class":211,"line":480},15,[482],{"type":21,"tag":209,"props":483,"children":484},{"style":448},[485],{"type":26,"value":486},"// ... elsewhere in your application ...\n",{"type":21,"tag":209,"props":488,"children":490},{"class":211,"line":489},16,[491,495,500,504,508,512,516,520,524,528,533,537,542,546,551,555,560,564,569,573,578],{"type":21,"tag":209,"props":492,"children":493},{"style":222},[494],{"type":26,"value":357},{"type":21,"tag":209,"props":496,"children":497},{"style":360},[498],{"type":26,"value":499},"trigger",{"type":21,"tag":209,"props":501,"children":502},{"style":222},[503],{"type":26,"value":368},{"type":21,"tag":209,"props":505,"children":506},{"style":263},[507],{"type":26,"value":373},{"type":21,"tag":209,"props":509,"children":510},{"style":222},[511],{"type":26,"value":378},{"type":21,"tag":209,"props":513,"children":514},{"style":263},[515],{"type":26,"value":383},{"type":21,"tag":209,"props":517,"children":518},{"style":222},[519],{"type":26,"value":378},{"type":21,"tag":209,"props":521,"children":522},{"style":263},[523],{"type":26,"value":392},{"type":21,"tag":209,"props":525,"children":526},{"style":222},[527],{"type":26,"value":408},{"type":21,"tag":209,"props":529,"children":530},{"style":233},[531],{"type":26,"value":532},"'event'",{"type":21,"tag":209,"props":534,"children":535},{"style":222},[536],{"type":26,"value":408},{"type":21,"tag":209,"props":538,"children":539},{"style":233},[540],{"type":26,"value":541},"'args'",{"type":21,"tag":209,"props":543,"children":544},{"style":222},[545],{"type":26,"value":408},{"type":21,"tag":209,"props":547,"children":548},{"style":263},[549],{"type":26,"value":550},"40",{"type":21,"tag":209,"props":552,"children":553},{"style":222},[554],{"type":26,"value":408},{"type":21,"tag":209,"props":556,"children":557},{"style":233},[558],{"type":26,"value":559},"'or'",{"type":21,"tag":209,"props":561,"children":562},{"style":222},[563],{"type":26,"value":408},{"type":21,"tag":209,"props":565,"children":566},{"style":233},[567],{"type":26,"value":568},"'as'",{"type":21,"tag":209,"props":570,"children":571},{"style":222},[572],{"type":26,"value":408},{"type":21,"tag":209,"props":574,"children":575},{"style":233},[576],{"type":26,"value":577},"'many as you like'",{"type":21,"tag":209,"props":579,"children":580},{"style":222},[581],{"type":26,"value":582},",)\n",{"type":21,"tag":193,"props":584,"children":586},{"id":585},"subscribe-to-all-events-on-a-channel",[587],{"type":26,"value":588},"Subscribe to all events on a channel",{"type":21,"tag":22,"props":590,"children":591},{},[592,594,600,602,608],{"type":26,"value":593},"Did you notice the ",{"type":21,"tag":63,"props":595,"children":597},{"className":596},[],[598],{"type":26,"value":599},"event.channel",{"type":26,"value":601}," structure of the event name in our example above? All events within VPubSub belong to a ",{"type":21,"tag":63,"props":603,"children":605},{"className":604},[],[606],{"type":26,"value":607},"channel",{"type":26,"value":609}," - a way of organizing events together. This also allows us to perform operations on a channel-basis, like subscribe to all events for that channel.",{"type":21,"tag":200,"props":611,"children":613},{"className":202,"code":612,"language":12,"meta":8,"style":8},"import {vent} from \"vpubsub\";\n\nconst EVENTS = {\n    PLAYER:{\n        START:'start.player',\n        END:'end.player',\n    }\n};\n\n/**\n * Subscribers to wildcard events will receive the channelEvent as the last argument,\n * allowing for disambiguation within the handler.\n */\nvent.on('*.player', (arg1, arg2, ..., channelEvent) => {\n    switch(channelEvent){\n        case 'start.player':\n            break;\n        case 'end.player':\n            break;\n        default:\n            break;\n    }\n});\n",[614],{"type":21,"tag":63,"props":615,"children":616},{"__ignoreMap":8},[617,640,647,666,673,688,703,710,717,724,732,740,748,756,814,827,845,858,875,887,900,912,920],{"type":21,"tag":209,"props":618,"children":619},{"class":211,"line":212},[620,624,628,632,636],{"type":21,"tag":209,"props":621,"children":622},{"style":216},[623],{"type":26,"value":219},{"type":21,"tag":209,"props":625,"children":626},{"style":222},[627],{"type":26,"value":225},{"type":21,"tag":209,"props":629,"children":630},{"style":216},[631],{"type":26,"value":230},{"type":21,"tag":209,"props":633,"children":634},{"style":233},[635],{"type":26,"value":236},{"type":21,"tag":209,"props":637,"children":638},{"style":222},[639],{"type":26,"value":241},{"type":21,"tag":209,"props":641,"children":642},{"class":211,"line":244},[643],{"type":21,"tag":209,"props":644,"children":645},{"emptyLinePlaceholder":248},[646],{"type":26,"value":251},{"type":21,"tag":209,"props":648,"children":649},{"class":211,"line":254},[650,654,658,662],{"type":21,"tag":209,"props":651,"children":652},{"style":216},[653],{"type":26,"value":260},{"type":21,"tag":209,"props":655,"children":656},{"style":263},[657],{"type":26,"value":266},{"type":21,"tag":209,"props":659,"children":660},{"style":216},[661],{"type":26,"value":271},{"type":21,"tag":209,"props":663,"children":664},{"style":222},[665],{"type":26,"value":276},{"type":21,"tag":209,"props":667,"children":668},{"class":211,"line":279},[669],{"type":21,"tag":209,"props":670,"children":671},{"style":222},[672],{"type":26,"value":285},{"type":21,"tag":209,"props":674,"children":675},{"class":211,"line":288},[676,680,684],{"type":21,"tag":209,"props":677,"children":678},{"style":222},[679],{"type":26,"value":294},{"type":21,"tag":209,"props":681,"children":682},{"style":233},[683],{"type":26,"value":299},{"type":21,"tag":209,"props":685,"children":686},{"style":222},[687],{"type":26,"value":304},{"type":21,"tag":209,"props":689,"children":690},{"class":211,"line":307},[691,695,699],{"type":21,"tag":209,"props":692,"children":693},{"style":222},[694],{"type":26,"value":313},{"type":21,"tag":209,"props":696,"children":697},{"style":233},[698],{"type":26,"value":318},{"type":21,"tag":209,"props":700,"children":701},{"style":222},[702],{"type":26,"value":304},{"type":21,"tag":209,"props":704,"children":705},{"class":211,"line":325},[706],{"type":21,"tag":209,"props":707,"children":708},{"style":222},[709],{"type":26,"value":331},{"type":21,"tag":209,"props":711,"children":712},{"class":211,"line":334},[713],{"type":21,"tag":209,"props":714,"children":715},{"style":222},[716],{"type":26,"value":340},{"type":21,"tag":209,"props":718,"children":719},{"class":211,"line":343},[720],{"type":21,"tag":209,"props":721,"children":722},{"emptyLinePlaceholder":248},[723],{"type":26,"value":251},{"type":21,"tag":209,"props":725,"children":726},{"class":211,"line":351},[727],{"type":21,"tag":209,"props":728,"children":729},{"style":448},[730],{"type":26,"value":731},"/**\n",{"type":21,"tag":209,"props":733,"children":734},{"class":211,"line":444},[735],{"type":21,"tag":209,"props":736,"children":737},{"style":448},[738],{"type":26,"value":739}," * Subscribers to wildcard events will receive the channelEvent as the last argument,\n",{"type":21,"tag":209,"props":741,"children":742},{"class":211,"line":454},[743],{"type":21,"tag":209,"props":744,"children":745},{"style":448},[746],{"type":26,"value":747}," * allowing for disambiguation within the handler.\n",{"type":21,"tag":209,"props":749,"children":750},{"class":211,"line":463},[751],{"type":21,"tag":209,"props":752,"children":753},{"style":448},[754],{"type":26,"value":755}," */\n",{"type":21,"tag":209,"props":757,"children":758},{"class":211,"line":472},[759,763,767,771,776,780,784,788,792,797,802,806,810],{"type":21,"tag":209,"props":760,"children":761},{"style":222},[762],{"type":26,"value":357},{"type":21,"tag":209,"props":764,"children":765},{"style":360},[766],{"type":26,"value":363},{"type":21,"tag":209,"props":768,"children":769},{"style":222},[770],{"type":26,"value":368},{"type":21,"tag":209,"props":772,"children":773},{"style":233},[774],{"type":26,"value":775},"'*.player'",{"type":21,"tag":209,"props":777,"children":778},{"style":222},[779],{"type":26,"value":397},{"type":21,"tag":209,"props":781,"children":782},{"style":400},[783],{"type":26,"value":403},{"type":21,"tag":209,"props":785,"children":786},{"style":222},[787],{"type":26,"value":408},{"type":21,"tag":209,"props":789,"children":790},{"style":400},[791],{"type":26,"value":413},{"type":21,"tag":209,"props":793,"children":794},{"style":222},[795],{"type":26,"value":796},", ..., ",{"type":21,"tag":209,"props":798,"children":799},{"style":400},[800],{"type":26,"value":801},"channelEvent",{"type":21,"tag":209,"props":803,"children":804},{"style":222},[805],{"type":26,"value":432},{"type":21,"tag":209,"props":807,"children":808},{"style":216},[809],{"type":26,"value":437},{"type":21,"tag":209,"props":811,"children":812},{"style":222},[813],{"type":26,"value":276},{"type":21,"tag":209,"props":815,"children":816},{"class":211,"line":480},[817,822],{"type":21,"tag":209,"props":818,"children":819},{"style":216},[820],{"type":26,"value":821},"    switch",{"type":21,"tag":209,"props":823,"children":824},{"style":222},[825],{"type":26,"value":826},"(channelEvent){\n",{"type":21,"tag":209,"props":828,"children":829},{"class":211,"line":489},[830,835,840],{"type":21,"tag":209,"props":831,"children":832},{"style":216},[833],{"type":26,"value":834},"        case",{"type":21,"tag":209,"props":836,"children":837},{"style":233},[838],{"type":26,"value":839}," 'start.player'",{"type":21,"tag":209,"props":841,"children":842},{"style":222},[843],{"type":26,"value":844},":\n",{"type":21,"tag":209,"props":846,"children":848},{"class":211,"line":847},17,[849,854],{"type":21,"tag":209,"props":850,"children":851},{"style":216},[852],{"type":26,"value":853},"            break",{"type":21,"tag":209,"props":855,"children":856},{"style":222},[857],{"type":26,"value":241},{"type":21,"tag":209,"props":859,"children":861},{"class":211,"line":860},18,[862,866,871],{"type":21,"tag":209,"props":863,"children":864},{"style":216},[865],{"type":26,"value":834},{"type":21,"tag":209,"props":867,"children":868},{"style":233},[869],{"type":26,"value":870}," 'end.player'",{"type":21,"tag":209,"props":872,"children":873},{"style":222},[874],{"type":26,"value":844},{"type":21,"tag":209,"props":876,"children":878},{"class":211,"line":877},19,[879,883],{"type":21,"tag":209,"props":880,"children":881},{"style":216},[882],{"type":26,"value":853},{"type":21,"tag":209,"props":884,"children":885},{"style":222},[886],{"type":26,"value":241},{"type":21,"tag":209,"props":888,"children":890},{"class":211,"line":889},20,[891,896],{"type":21,"tag":209,"props":892,"children":893},{"style":216},[894],{"type":26,"value":895},"        default",{"type":21,"tag":209,"props":897,"children":898},{"style":222},[899],{"type":26,"value":844},{"type":21,"tag":209,"props":901,"children":903},{"class":211,"line":902},21,[904,908],{"type":21,"tag":209,"props":905,"children":906},{"style":216},[907],{"type":26,"value":853},{"type":21,"tag":209,"props":909,"children":910},{"style":222},[911],{"type":26,"value":241},{"type":21,"tag":209,"props":913,"children":915},{"class":211,"line":914},22,[916],{"type":21,"tag":209,"props":917,"children":918},{"style":222},[919],{"type":26,"value":331},{"type":21,"tag":209,"props":921,"children":923},{"class":211,"line":922},23,[924],{"type":21,"tag":209,"props":925,"children":926},{"style":222},[927],{"type":26,"value":469},{"type":21,"tag":193,"props":929,"children":931},{"id":930},"subscribe-to-all-events",[932],{"type":26,"value":933},"Subscribe to all events",{"type":21,"tag":22,"props":935,"children":936},{},[937,939,945,947,952],{"type":26,"value":938},"While not recommended, you can add a subscriber to all events by subscribing to the wildcard ",{"type":21,"tag":63,"props":940,"children":942},{"className":941},[],[943],{"type":26,"value":944},"*",{"type":26,"value":946}," event on the wildcard ",{"type":21,"tag":63,"props":948,"children":950},{"className":949},[],[951],{"type":26,"value":944},{"type":26,"value":953}," channel. This could be used for debugging events, as you'll be able to see all traffic across the bus:",{"type":21,"tag":200,"props":955,"children":957},{"className":202,"code":956,"language":12,"meta":8,"style":8},"/**\n * As with wildcard channel events, the channelEvent will always be the last argument\n * when subscribing to all events.\n */\nvent.on('*.*', (arg1, arg2, ..., channelEvent) => {\n    console.log(arg1, channelEvent);\n});\n",[958],{"type":21,"tag":63,"props":959,"children":960},{"__ignoreMap":8},[961,968,976,984,991,1047,1065],{"type":21,"tag":209,"props":962,"children":963},{"class":211,"line":212},[964],{"type":21,"tag":209,"props":965,"children":966},{"style":448},[967],{"type":26,"value":731},{"type":21,"tag":209,"props":969,"children":970},{"class":211,"line":244},[971],{"type":21,"tag":209,"props":972,"children":973},{"style":448},[974],{"type":26,"value":975}," * As with wildcard channel events, the channelEvent will always be the last argument\n",{"type":21,"tag":209,"props":977,"children":978},{"class":211,"line":254},[979],{"type":21,"tag":209,"props":980,"children":981},{"style":448},[982],{"type":26,"value":983}," * when subscribing to all events.\n",{"type":21,"tag":209,"props":985,"children":986},{"class":211,"line":279},[987],{"type":21,"tag":209,"props":988,"children":989},{"style":448},[990],{"type":26,"value":755},{"type":21,"tag":209,"props":992,"children":993},{"class":211,"line":288},[994,998,1002,1006,1011,1015,1019,1023,1027,1031,1035,1039,1043],{"type":21,"tag":209,"props":995,"children":996},{"style":222},[997],{"type":26,"value":357},{"type":21,"tag":209,"props":999,"children":1000},{"style":360},[1001],{"type":26,"value":363},{"type":21,"tag":209,"props":1003,"children":1004},{"style":222},[1005],{"type":26,"value":368},{"type":21,"tag":209,"props":1007,"children":1008},{"style":233},[1009],{"type":26,"value":1010},"'*.*'",{"type":21,"tag":209,"props":1012,"children":1013},{"style":222},[1014],{"type":26,"value":397},{"type":21,"tag":209,"props":1016,"children":1017},{"style":400},[1018],{"type":26,"value":403},{"type":21,"tag":209,"props":1020,"children":1021},{"style":222},[1022],{"type":26,"value":408},{"type":21,"tag":209,"props":1024,"children":1025},{"style":400},[1026],{"type":26,"value":413},{"type":21,"tag":209,"props":1028,"children":1029},{"style":222},[1030],{"type":26,"value":796},{"type":21,"tag":209,"props":1032,"children":1033},{"style":400},[1034],{"type":26,"value":801},{"type":21,"tag":209,"props":1036,"children":1037},{"style":222},[1038],{"type":26,"value":432},{"type":21,"tag":209,"props":1040,"children":1041},{"style":216},[1042],{"type":26,"value":437},{"type":21,"tag":209,"props":1044,"children":1045},{"style":222},[1046],{"type":26,"value":276},{"type":21,"tag":209,"props":1048,"children":1049},{"class":211,"line":307},[1050,1055,1060],{"type":21,"tag":209,"props":1051,"children":1052},{"style":222},[1053],{"type":26,"value":1054},"    console.",{"type":21,"tag":209,"props":1056,"children":1057},{"style":360},[1058],{"type":26,"value":1059},"log",{"type":21,"tag":209,"props":1061,"children":1062},{"style":222},[1063],{"type":26,"value":1064},"(arg1, channelEvent);\n",{"type":21,"tag":209,"props":1066,"children":1067},{"class":211,"line":325},[1068],{"type":21,"tag":209,"props":1069,"children":1070},{"style":222},[1071],{"type":26,"value":469},{"type":21,"tag":193,"props":1073,"children":1075},{"id":1074},"requests",[1076],{"type":26,"value":1077},"Requests",{"type":21,"tag":22,"props":1079,"children":1080},{},[1081,1083,1089],{"type":26,"value":1082},"In addition to one-way event publishing, we can also perform two-way event ",{"type":21,"tag":1084,"props":1085,"children":1086},"em",{},[1087],{"type":26,"value":1088},"messaging",{"type":26,"value":1090}," by making requests. Requests always return a promise that resolves with the responses from all subscribers.",{"type":21,"tag":200,"props":1092,"children":1094},{"className":202,"code":1093,"language":12,"meta":8,"style":8},"import {vent} from \"vpubsub\";\n\nconst EVENTS = {\n    PLAYER:{\n        START:'start.player',\n        END:'end.player',\n    }\n};\n\nvent.on(EVENTS.PLAYER.START, () => {\n    // Perform some work and return a response.\n    const data = {...};\n    return data;\n});\n\n// ... elsewhere in your application ...\n\nvent.request(EVENTS.PLAYER.START, async(res) => {\n    // Do something useful with the response(s) from the subscriber(s).\n    const [resp1] = await res;\n    console.log(resp1);\n});\n",[1095],{"type":21,"tag":63,"props":1096,"children":1097},{"__ignoreMap":8},[1098,1121,1128,1147,1154,1169,1184,1191,1198,1205,1253,1261,1291,1304,1311,1318,1325,1332,1398,1406,1443,1459],{"type":21,"tag":209,"props":1099,"children":1100},{"class":211,"line":212},[1101,1105,1109,1113,1117],{"type":21,"tag":209,"props":1102,"children":1103},{"style":216},[1104],{"type":26,"value":219},{"type":21,"tag":209,"props":1106,"children":1107},{"style":222},[1108],{"type":26,"value":225},{"type":21,"tag":209,"props":1110,"children":1111},{"style":216},[1112],{"type":26,"value":230},{"type":21,"tag":209,"props":1114,"children":1115},{"style":233},[1116],{"type":26,"value":236},{"type":21,"tag":209,"props":1118,"children":1119},{"style":222},[1120],{"type":26,"value":241},{"type":21,"tag":209,"props":1122,"children":1123},{"class":211,"line":244},[1124],{"type":21,"tag":209,"props":1125,"children":1126},{"emptyLinePlaceholder":248},[1127],{"type":26,"value":251},{"type":21,"tag":209,"props":1129,"children":1130},{"class":211,"line":254},[1131,1135,1139,1143],{"type":21,"tag":209,"props":1132,"children":1133},{"style":216},[1134],{"type":26,"value":260},{"type":21,"tag":209,"props":1136,"children":1137},{"style":263},[1138],{"type":26,"value":266},{"type":21,"tag":209,"props":1140,"children":1141},{"style":216},[1142],{"type":26,"value":271},{"type":21,"tag":209,"props":1144,"children":1145},{"style":222},[1146],{"type":26,"value":276},{"type":21,"tag":209,"props":1148,"children":1149},{"class":211,"line":279},[1150],{"type":21,"tag":209,"props":1151,"children":1152},{"style":222},[1153],{"type":26,"value":285},{"type":21,"tag":209,"props":1155,"children":1156},{"class":211,"line":288},[1157,1161,1165],{"type":21,"tag":209,"props":1158,"children":1159},{"style":222},[1160],{"type":26,"value":294},{"type":21,"tag":209,"props":1162,"children":1163},{"style":233},[1164],{"type":26,"value":299},{"type":21,"tag":209,"props":1166,"children":1167},{"style":222},[1168],{"type":26,"value":304},{"type":21,"tag":209,"props":1170,"children":1171},{"class":211,"line":307},[1172,1176,1180],{"type":21,"tag":209,"props":1173,"children":1174},{"style":222},[1175],{"type":26,"value":313},{"type":21,"tag":209,"props":1177,"children":1178},{"style":233},[1179],{"type":26,"value":318},{"type":21,"tag":209,"props":1181,"children":1182},{"style":222},[1183],{"type":26,"value":304},{"type":21,"tag":209,"props":1185,"children":1186},{"class":211,"line":325},[1187],{"type":21,"tag":209,"props":1188,"children":1189},{"style":222},[1190],{"type":26,"value":331},{"type":21,"tag":209,"props":1192,"children":1193},{"class":211,"line":334},[1194],{"type":21,"tag":209,"props":1195,"children":1196},{"style":222},[1197],{"type":26,"value":340},{"type":21,"tag":209,"props":1199,"children":1200},{"class":211,"line":343},[1201],{"type":21,"tag":209,"props":1202,"children":1203},{"emptyLinePlaceholder":248},[1204],{"type":26,"value":251},{"type":21,"tag":209,"props":1206,"children":1207},{"class":211,"line":351},[1208,1212,1216,1220,1224,1228,1232,1236,1240,1245,1249],{"type":21,"tag":209,"props":1209,"children":1210},{"style":222},[1211],{"type":26,"value":357},{"type":21,"tag":209,"props":1213,"children":1214},{"style":360},[1215],{"type":26,"value":363},{"type":21,"tag":209,"props":1217,"children":1218},{"style":222},[1219],{"type":26,"value":368},{"type":21,"tag":209,"props":1221,"children":1222},{"style":263},[1223],{"type":26,"value":373},{"type":21,"tag":209,"props":1225,"children":1226},{"style":222},[1227],{"type":26,"value":378},{"type":21,"tag":209,"props":1229,"children":1230},{"style":263},[1231],{"type":26,"value":383},{"type":21,"tag":209,"props":1233,"children":1234},{"style":222},[1235],{"type":26,"value":378},{"type":21,"tag":209,"props":1237,"children":1238},{"style":263},[1239],{"type":26,"value":392},{"type":21,"tag":209,"props":1241,"children":1242},{"style":222},[1243],{"type":26,"value":1244},", () ",{"type":21,"tag":209,"props":1246,"children":1247},{"style":216},[1248],{"type":26,"value":437},{"type":21,"tag":209,"props":1250,"children":1251},{"style":222},[1252],{"type":26,"value":276},{"type":21,"tag":209,"props":1254,"children":1255},{"class":211,"line":444},[1256],{"type":21,"tag":209,"props":1257,"children":1258},{"style":448},[1259],{"type":26,"value":1260},"    // Perform some work and return a response.\n",{"type":21,"tag":209,"props":1262,"children":1263},{"class":211,"line":454},[1264,1269,1274,1278,1283,1287],{"type":21,"tag":209,"props":1265,"children":1266},{"style":216},[1267],{"type":26,"value":1268},"    const",{"type":21,"tag":209,"props":1270,"children":1271},{"style":263},[1272],{"type":26,"value":1273}," data",{"type":21,"tag":209,"props":1275,"children":1276},{"style":216},[1277],{"type":26,"value":271},{"type":21,"tag":209,"props":1279,"children":1280},{"style":222},[1281],{"type":26,"value":1282}," {",{"type":21,"tag":209,"props":1284,"children":1285},{"style":216},[1286],{"type":26,"value":422},{"type":21,"tag":209,"props":1288,"children":1289},{"style":222},[1290],{"type":26,"value":340},{"type":21,"tag":209,"props":1292,"children":1293},{"class":211,"line":463},[1294,1299],{"type":21,"tag":209,"props":1295,"children":1296},{"style":216},[1297],{"type":26,"value":1298},"    return",{"type":21,"tag":209,"props":1300,"children":1301},{"style":222},[1302],{"type":26,"value":1303}," data;\n",{"type":21,"tag":209,"props":1305,"children":1306},{"class":211,"line":472},[1307],{"type":21,"tag":209,"props":1308,"children":1309},{"style":222},[1310],{"type":26,"value":469},{"type":21,"tag":209,"props":1312,"children":1313},{"class":211,"line":480},[1314],{"type":21,"tag":209,"props":1315,"children":1316},{"emptyLinePlaceholder":248},[1317],{"type":26,"value":251},{"type":21,"tag":209,"props":1319,"children":1320},{"class":211,"line":489},[1321],{"type":21,"tag":209,"props":1322,"children":1323},{"style":448},[1324],{"type":26,"value":486},{"type":21,"tag":209,"props":1326,"children":1327},{"class":211,"line":847},[1328],{"type":21,"tag":209,"props":1329,"children":1330},{"emptyLinePlaceholder":248},[1331],{"type":26,"value":251},{"type":21,"tag":209,"props":1333,"children":1334},{"class":211,"line":860},[1335,1339,1344,1348,1352,1356,1360,1364,1368,1372,1377,1381,1386,1390,1394],{"type":21,"tag":209,"props":1336,"children":1337},{"style":222},[1338],{"type":26,"value":357},{"type":21,"tag":209,"props":1340,"children":1341},{"style":360},[1342],{"type":26,"value":1343},"request",{"type":21,"tag":209,"props":1345,"children":1346},{"style":222},[1347],{"type":26,"value":368},{"type":21,"tag":209,"props":1349,"children":1350},{"style":263},[1351],{"type":26,"value":373},{"type":21,"tag":209,"props":1353,"children":1354},{"style":222},[1355],{"type":26,"value":378},{"type":21,"tag":209,"props":1357,"children":1358},{"style":263},[1359],{"type":26,"value":383},{"type":21,"tag":209,"props":1361,"children":1362},{"style":222},[1363],{"type":26,"value":378},{"type":21,"tag":209,"props":1365,"children":1366},{"style":263},[1367],{"type":26,"value":392},{"type":21,"tag":209,"props":1369,"children":1370},{"style":222},[1371],{"type":26,"value":408},{"type":21,"tag":209,"props":1373,"children":1374},{"style":216},[1375],{"type":26,"value":1376},"async",{"type":21,"tag":209,"props":1378,"children":1379},{"style":222},[1380],{"type":26,"value":368},{"type":21,"tag":209,"props":1382,"children":1383},{"style":400},[1384],{"type":26,"value":1385},"res",{"type":21,"tag":209,"props":1387,"children":1388},{"style":222},[1389],{"type":26,"value":432},{"type":21,"tag":209,"props":1391,"children":1392},{"style":216},[1393],{"type":26,"value":437},{"type":21,"tag":209,"props":1395,"children":1396},{"style":222},[1397],{"type":26,"value":276},{"type":21,"tag":209,"props":1399,"children":1400},{"class":211,"line":877},[1401],{"type":21,"tag":209,"props":1402,"children":1403},{"style":448},[1404],{"type":26,"value":1405},"    // Do something useful with the response(s) from the subscriber(s).\n",{"type":21,"tag":209,"props":1407,"children":1408},{"class":211,"line":889},[1409,1413,1418,1423,1428,1433,1438],{"type":21,"tag":209,"props":1410,"children":1411},{"style":216},[1412],{"type":26,"value":1268},{"type":21,"tag":209,"props":1414,"children":1415},{"style":222},[1416],{"type":26,"value":1417}," [",{"type":21,"tag":209,"props":1419,"children":1420},{"style":263},[1421],{"type":26,"value":1422},"resp1",{"type":21,"tag":209,"props":1424,"children":1425},{"style":222},[1426],{"type":26,"value":1427},"] ",{"type":21,"tag":209,"props":1429,"children":1430},{"style":216},[1431],{"type":26,"value":1432},"=",{"type":21,"tag":209,"props":1434,"children":1435},{"style":216},[1436],{"type":26,"value":1437}," await",{"type":21,"tag":209,"props":1439,"children":1440},{"style":222},[1441],{"type":26,"value":1442}," res;\n",{"type":21,"tag":209,"props":1444,"children":1445},{"class":211,"line":902},[1446,1450,1454],{"type":21,"tag":209,"props":1447,"children":1448},{"style":222},[1449],{"type":26,"value":1054},{"type":21,"tag":209,"props":1451,"children":1452},{"style":360},[1453],{"type":26,"value":1059},{"type":21,"tag":209,"props":1455,"children":1456},{"style":222},[1457],{"type":26,"value":1458},"(resp1);\n",{"type":21,"tag":209,"props":1460,"children":1461},{"class":211,"line":914},[1462],{"type":21,"tag":209,"props":1463,"children":1464},{"style":222},[1465],{"type":26,"value":469},{"type":21,"tag":22,"props":1467,"children":1468},{},[1469,1471,1476,1478,1483],{"type":26,"value":1470},"The same special wildcard channel event and global wildcard that you can use with ",{"type":21,"tag":63,"props":1472,"children":1474},{"className":1473},[],[1475],{"type":26,"value":499},{"type":26,"value":1477}," also apply to ",{"type":21,"tag":63,"props":1479,"children":1481},{"className":1480},[],[1482],{"type":26,"value":1343},{"type":26,"value":1484},", as detailed above.",{"type":21,"tag":51,"props":1486,"children":1488},{"id":1487},"how-does-it-work-with-vue",[1489],{"type":26,"value":1490},"How Does It Work With Vue?",{"type":21,"tag":22,"props":1492,"children":1493},{},[1494],{"type":26,"value":1495},"VPubSub comes with built-in support for using it as a plugin with Vue 3. First, let's install it, and then we'll take a look at using it with the Options or Composition APIs.",{"type":21,"tag":193,"props":1497,"children":1499},{"id":1498},"installation",[1500],{"type":26,"value":1501},"Installation",{"type":21,"tag":22,"props":1503,"children":1504},{},[1505,1507,1513],{"type":26,"value":1506},"Let's create a ",{"type":21,"tag":63,"props":1508,"children":1510},{"className":1509},[],[1511],{"type":26,"value":1512},"plugins/vent.js",{"type":26,"value":1514}," file, that looks like this:",{"type":21,"tag":200,"props":1516,"children":1518},{"className":202,"code":1517,"language":12,"meta":8,"style":8},"/**\n * Return our vent utility as a plugin in Vue for install.\n */\n\nimport {install} from \"vpubsub\";\n\nexport default install;\n",[1519],{"type":21,"tag":63,"props":1520,"children":1521},{"__ignoreMap":8},[1522,1529,1537,1544,1551,1575,1582],{"type":21,"tag":209,"props":1523,"children":1524},{"class":211,"line":212},[1525],{"type":21,"tag":209,"props":1526,"children":1527},{"style":448},[1528],{"type":26,"value":731},{"type":21,"tag":209,"props":1530,"children":1531},{"class":211,"line":244},[1532],{"type":21,"tag":209,"props":1533,"children":1534},{"style":448},[1535],{"type":26,"value":1536}," * Return our vent utility as a plugin in Vue for install.\n",{"type":21,"tag":209,"props":1538,"children":1539},{"class":211,"line":254},[1540],{"type":21,"tag":209,"props":1541,"children":1542},{"style":448},[1543],{"type":26,"value":755},{"type":21,"tag":209,"props":1545,"children":1546},{"class":211,"line":279},[1547],{"type":21,"tag":209,"props":1548,"children":1549},{"emptyLinePlaceholder":248},[1550],{"type":26,"value":251},{"type":21,"tag":209,"props":1552,"children":1553},{"class":211,"line":288},[1554,1558,1563,1567,1571],{"type":21,"tag":209,"props":1555,"children":1556},{"style":216},[1557],{"type":26,"value":219},{"type":21,"tag":209,"props":1559,"children":1560},{"style":222},[1561],{"type":26,"value":1562}," {install} ",{"type":21,"tag":209,"props":1564,"children":1565},{"style":216},[1566],{"type":26,"value":230},{"type":21,"tag":209,"props":1568,"children":1569},{"style":233},[1570],{"type":26,"value":236},{"type":21,"tag":209,"props":1572,"children":1573},{"style":222},[1574],{"type":26,"value":241},{"type":21,"tag":209,"props":1576,"children":1577},{"class":211,"line":307},[1578],{"type":21,"tag":209,"props":1579,"children":1580},{"emptyLinePlaceholder":248},[1581],{"type":26,"value":251},{"type":21,"tag":209,"props":1583,"children":1584},{"class":211,"line":325},[1585,1590,1595],{"type":21,"tag":209,"props":1586,"children":1587},{"style":216},[1588],{"type":26,"value":1589},"export",{"type":21,"tag":209,"props":1591,"children":1592},{"style":216},[1593],{"type":26,"value":1594}," default",{"type":21,"tag":209,"props":1596,"children":1597},{"style":222},[1598],{"type":26,"value":1599}," install;\n",{"type":21,"tag":22,"props":1601,"children":1602},{},[1603,1605,1611],{"type":26,"value":1604},"Then, in ",{"type":21,"tag":63,"props":1606,"children":1608},{"className":1607},[],[1609],{"type":26,"value":1610},"main.js",{"type":26,"value":1612}," (your Vue app's point of entry), we can use it like so:",{"type":21,"tag":200,"props":1614,"children":1616},{"className":202,"code":1615,"language":12,"meta":8,"style":8},"import {createApp} from 'vue';\nimport vent from \"plugins/vent\";\nimport App from \"App.vue\";\n\nconst vue = createApp(App);\n\nvue.use(vent);\n",[1617],{"type":21,"tag":63,"props":1618,"children":1619},{"__ignoreMap":8},[1620,1645,1670,1695,1702,1728,1735],{"type":21,"tag":209,"props":1621,"children":1622},{"class":211,"line":212},[1623,1627,1632,1636,1641],{"type":21,"tag":209,"props":1624,"children":1625},{"style":216},[1626],{"type":26,"value":219},{"type":21,"tag":209,"props":1628,"children":1629},{"style":222},[1630],{"type":26,"value":1631}," {createApp} ",{"type":21,"tag":209,"props":1633,"children":1634},{"style":216},[1635],{"type":26,"value":230},{"type":21,"tag":209,"props":1637,"children":1638},{"style":233},[1639],{"type":26,"value":1640}," 'vue'",{"type":21,"tag":209,"props":1642,"children":1643},{"style":222},[1644],{"type":26,"value":241},{"type":21,"tag":209,"props":1646,"children":1647},{"class":211,"line":244},[1648,1652,1657,1661,1666],{"type":21,"tag":209,"props":1649,"children":1650},{"style":216},[1651],{"type":26,"value":219},{"type":21,"tag":209,"props":1653,"children":1654},{"style":222},[1655],{"type":26,"value":1656}," vent ",{"type":21,"tag":209,"props":1658,"children":1659},{"style":216},[1660],{"type":26,"value":230},{"type":21,"tag":209,"props":1662,"children":1663},{"style":233},[1664],{"type":26,"value":1665}," \"plugins/vent\"",{"type":21,"tag":209,"props":1667,"children":1668},{"style":222},[1669],{"type":26,"value":241},{"type":21,"tag":209,"props":1671,"children":1672},{"class":211,"line":254},[1673,1677,1682,1686,1691],{"type":21,"tag":209,"props":1674,"children":1675},{"style":216},[1676],{"type":26,"value":219},{"type":21,"tag":209,"props":1678,"children":1679},{"style":222},[1680],{"type":26,"value":1681}," App ",{"type":21,"tag":209,"props":1683,"children":1684},{"style":216},[1685],{"type":26,"value":230},{"type":21,"tag":209,"props":1687,"children":1688},{"style":233},[1689],{"type":26,"value":1690}," \"App.vue\"",{"type":21,"tag":209,"props":1692,"children":1693},{"style":222},[1694],{"type":26,"value":241},{"type":21,"tag":209,"props":1696,"children":1697},{"class":211,"line":279},[1698],{"type":21,"tag":209,"props":1699,"children":1700},{"emptyLinePlaceholder":248},[1701],{"type":26,"value":251},{"type":21,"tag":209,"props":1703,"children":1704},{"class":211,"line":288},[1705,1709,1714,1718,1723],{"type":21,"tag":209,"props":1706,"children":1707},{"style":216},[1708],{"type":26,"value":260},{"type":21,"tag":209,"props":1710,"children":1711},{"style":263},[1712],{"type":26,"value":1713}," vue",{"type":21,"tag":209,"props":1715,"children":1716},{"style":216},[1717],{"type":26,"value":271},{"type":21,"tag":209,"props":1719,"children":1720},{"style":360},[1721],{"type":26,"value":1722}," createApp",{"type":21,"tag":209,"props":1724,"children":1725},{"style":222},[1726],{"type":26,"value":1727},"(App);\n",{"type":21,"tag":209,"props":1729,"children":1730},{"class":211,"line":307},[1731],{"type":21,"tag":209,"props":1732,"children":1733},{"emptyLinePlaceholder":248},[1734],{"type":26,"value":251},{"type":21,"tag":209,"props":1736,"children":1737},{"class":211,"line":325},[1738,1743,1748],{"type":21,"tag":209,"props":1739,"children":1740},{"style":222},[1741],{"type":26,"value":1742},"vue.",{"type":21,"tag":209,"props":1744,"children":1745},{"style":360},[1746],{"type":26,"value":1747},"use",{"type":21,"tag":209,"props":1749,"children":1750},{"style":222},[1751],{"type":26,"value":1752},"(vent);\n",{"type":21,"tag":22,"props":1754,"children":1755},{},[1756],{"type":26,"value":1757},"You can also skip creating a plugin wrapper, and use it like so:",{"type":21,"tag":200,"props":1759,"children":1761},{"className":202,"code":1760,"language":12,"meta":8,"style":8},"import {install as vent} from \"vpubsub\";\nimport {createApp} from 'vue';\nimport App from \"App.vue\";\n\nconst vue = createApp(App);\n\nvue.use(vent);\n",[1762],{"type":21,"tag":63,"props":1763,"children":1764},{"__ignoreMap":8},[1765,1799,1822,1845,1852,1875,1882],{"type":21,"tag":209,"props":1766,"children":1767},{"class":211,"line":212},[1768,1772,1777,1782,1787,1791,1795],{"type":21,"tag":209,"props":1769,"children":1770},{"style":216},[1771],{"type":26,"value":219},{"type":21,"tag":209,"props":1773,"children":1774},{"style":222},[1775],{"type":26,"value":1776}," {install ",{"type":21,"tag":209,"props":1778,"children":1779},{"style":216},[1780],{"type":26,"value":1781},"as",{"type":21,"tag":209,"props":1783,"children":1784},{"style":222},[1785],{"type":26,"value":1786}," vent} ",{"type":21,"tag":209,"props":1788,"children":1789},{"style":216},[1790],{"type":26,"value":230},{"type":21,"tag":209,"props":1792,"children":1793},{"style":233},[1794],{"type":26,"value":236},{"type":21,"tag":209,"props":1796,"children":1797},{"style":222},[1798],{"type":26,"value":241},{"type":21,"tag":209,"props":1800,"children":1801},{"class":211,"line":244},[1802,1806,1810,1814,1818],{"type":21,"tag":209,"props":1803,"children":1804},{"style":216},[1805],{"type":26,"value":219},{"type":21,"tag":209,"props":1807,"children":1808},{"style":222},[1809],{"type":26,"value":1631},{"type":21,"tag":209,"props":1811,"children":1812},{"style":216},[1813],{"type":26,"value":230},{"type":21,"tag":209,"props":1815,"children":1816},{"style":233},[1817],{"type":26,"value":1640},{"type":21,"tag":209,"props":1819,"children":1820},{"style":222},[1821],{"type":26,"value":241},{"type":21,"tag":209,"props":1823,"children":1824},{"class":211,"line":254},[1825,1829,1833,1837,1841],{"type":21,"tag":209,"props":1826,"children":1827},{"style":216},[1828],{"type":26,"value":219},{"type":21,"tag":209,"props":1830,"children":1831},{"style":222},[1832],{"type":26,"value":1681},{"type":21,"tag":209,"props":1834,"children":1835},{"style":216},[1836],{"type":26,"value":230},{"type":21,"tag":209,"props":1838,"children":1839},{"style":233},[1840],{"type":26,"value":1690},{"type":21,"tag":209,"props":1842,"children":1843},{"style":222},[1844],{"type":26,"value":241},{"type":21,"tag":209,"props":1846,"children":1847},{"class":211,"line":279},[1848],{"type":21,"tag":209,"props":1849,"children":1850},{"emptyLinePlaceholder":248},[1851],{"type":26,"value":251},{"type":21,"tag":209,"props":1853,"children":1854},{"class":211,"line":288},[1855,1859,1863,1867,1871],{"type":21,"tag":209,"props":1856,"children":1857},{"style":216},[1858],{"type":26,"value":260},{"type":21,"tag":209,"props":1860,"children":1861},{"style":263},[1862],{"type":26,"value":1713},{"type":21,"tag":209,"props":1864,"children":1865},{"style":216},[1866],{"type":26,"value":271},{"type":21,"tag":209,"props":1868,"children":1869},{"style":360},[1870],{"type":26,"value":1722},{"type":21,"tag":209,"props":1872,"children":1873},{"style":222},[1874],{"type":26,"value":1727},{"type":21,"tag":209,"props":1876,"children":1877},{"class":211,"line":307},[1878],{"type":21,"tag":209,"props":1879,"children":1880},{"emptyLinePlaceholder":248},[1881],{"type":26,"value":251},{"type":21,"tag":209,"props":1883,"children":1884},{"class":211,"line":325},[1885,1889,1893],{"type":21,"tag":209,"props":1886,"children":1887},{"style":222},[1888],{"type":26,"value":1742},{"type":21,"tag":209,"props":1890,"children":1891},{"style":360},[1892],{"type":26,"value":1747},{"type":21,"tag":209,"props":1894,"children":1895},{"style":222},[1896],{"type":26,"value":1752},{"type":21,"tag":193,"props":1898,"children":1900},{"id":1899},"options-api",[1901],{"type":26,"value":180},{"type":21,"tag":22,"props":1903,"children":1904},{},[1905,1907,1913,1915,1921,1923,1929,1931,1936],{"type":26,"value":1906},"When installed as a Vue plugin, VPubSub adds a new element to the Options API, the ",{"type":21,"tag":63,"props":1908,"children":1910},{"className":1909},[],[1911],{"type":26,"value":1912},"vent",{"type":26,"value":1914}," option. This should be an object similar to ",{"type":21,"tag":63,"props":1916,"children":1918},{"className":1917},[],[1919],{"type":26,"value":1920},"methods",{"type":26,"value":1922}," or ",{"type":21,"tag":63,"props":1924,"children":1926},{"className":1925},[],[1927],{"type":26,"value":1928},"computed",{"type":26,"value":1930}," in your component, that has the events as the key and ",{"type":21,"tag":1084,"props":1932,"children":1933},{},[1934],{"type":26,"value":1935},"either",{"type":26,"value":1937}," a direct function as the subscriber, or the name of a method in your component as a string.",{"type":21,"tag":22,"props":1939,"children":1940},{},[1941,1943,1948,1950,1956,1958,1964],{"type":26,"value":1942},"You also gain access to the ",{"type":21,"tag":63,"props":1944,"children":1946},{"className":1945},[],[1947],{"type":26,"value":1912},{"type":26,"value":1949}," singleton as a globally available component property, via ",{"type":21,"tag":63,"props":1951,"children":1953},{"className":1952},[],[1954],{"type":26,"value":1955},"$vent",{"type":26,"value":1957},"; you can reference it from within any component via ",{"type":21,"tag":63,"props":1959,"children":1961},{"className":1960},[],[1962],{"type":26,"value":1963},"this.$vent",{"type":26,"value":378},{"type":21,"tag":22,"props":1966,"children":1967},{},[1968],{"type":26,"value":1969},"For example:",{"type":21,"tag":200,"props":1971,"children":1974},{"className":1972,"code":1973,"language":13,"meta":8,"style":8},"language-vue shiki shiki-themes github-light github-dark","\u003Ctemplate>\n    \u003Cdiv>\u003C!-- ...Your template contents... -->\u003C/div>\n\u003C/template>\n\u003Cscript lang=\"js\">\nconst EVENTS = {\n    PLAYER:{\n        START:'start.player',\n        END:'end.player',\n    }\n};\n\nexport default {\n    name: \"VComponent\",\n    props:{\n        vprop:{\n            type:Boolean,\n            default:true,\n        }\n        // ... Your Props ...\n    },\n    vent:{\n        // Indirect binding - the named function within this component will be bound.\n        [EVENTS.PLAYER.START]:'recalcPoints',\n        // Direct binding - this function will be bound.\n        [EVENTS.PLAYER.END](arg1, arg2){\n            // Called whenever the `EVENTS.PLAYER.END` event is triggered or requested.\n        }\n    },\n    methods:{\n        /**\n         * This method will be called whenever the `EVENTS.PLAYER.START` event is\n         * triggered or requested.\n         */\n        recalcPoints(arg1, arg2){\n            // Because the `vent` events are bound to the component, you can use\n            // this to get props, data, computed, etc. of the component.\n            console.log(this.vprop);\n        },\n        /**\n         * Trigger an event as a result of doing something.\n         */\n        doSomething(){\n            this.$vent.trigger(EVENTS.PLAYER.END);\n        },\n        /**\n         * Request replies from subscribers.\n         */\n        getSomething(){\n            this.$vent.request(EVENTS.PLAYER.END).then((res) => {\n                const [resp] = res;\n                console.log(resp);\n            });\n        },\n    },\n};\n\u003C/script>\n",[1975],{"type":21,"tag":63,"props":1976,"children":1977},{"__ignoreMap":8},[1978,1997,2033,2048,2078,2097,2104,2119,2134,2141,2148,2155,2170,2187,2195,2203,2211,2228,2236,2244,2252,2260,2268,2310,2319,2370,2379,2387,2395,2404,2413,2422,2431,2440,2469,2478,2487,2514,2523,2531,2540,2548,2562,2609,2617,2625,2634,2642,2655,2726,2756,2774,2783,2791,2799,2807],{"type":21,"tag":209,"props":1979,"children":1980},{"class":211,"line":212},[1981,1986,1992],{"type":21,"tag":209,"props":1982,"children":1983},{"style":222},[1984],{"type":26,"value":1985},"\u003C",{"type":21,"tag":209,"props":1987,"children":1989},{"style":1988},"--shiki-default:#22863A;--shiki-dark:#85E89D",[1990],{"type":26,"value":1991},"template",{"type":21,"tag":209,"props":1993,"children":1994},{"style":222},[1995],{"type":26,"value":1996},">\n",{"type":21,"tag":209,"props":1998,"children":1999},{"class":211,"line":244},[2000,2005,2010,2015,2020,2025,2029],{"type":21,"tag":209,"props":2001,"children":2002},{"style":222},[2003],{"type":26,"value":2004},"    \u003C",{"type":21,"tag":209,"props":2006,"children":2007},{"style":1988},[2008],{"type":26,"value":2009},"div",{"type":21,"tag":209,"props":2011,"children":2012},{"style":222},[2013],{"type":26,"value":2014},">",{"type":21,"tag":209,"props":2016,"children":2017},{"style":448},[2018],{"type":26,"value":2019},"\u003C!-- ...Your template contents... -->",{"type":21,"tag":209,"props":2021,"children":2022},{"style":222},[2023],{"type":26,"value":2024},"\u003C/",{"type":21,"tag":209,"props":2026,"children":2027},{"style":1988},[2028],{"type":26,"value":2009},{"type":21,"tag":209,"props":2030,"children":2031},{"style":222},[2032],{"type":26,"value":1996},{"type":21,"tag":209,"props":2034,"children":2035},{"class":211,"line":254},[2036,2040,2044],{"type":21,"tag":209,"props":2037,"children":2038},{"style":222},[2039],{"type":26,"value":2024},{"type":21,"tag":209,"props":2041,"children":2042},{"style":1988},[2043],{"type":26,"value":1991},{"type":21,"tag":209,"props":2045,"children":2046},{"style":222},[2047],{"type":26,"value":1996},{"type":21,"tag":209,"props":2049,"children":2050},{"class":211,"line":279},[2051,2055,2060,2065,2069,2074],{"type":21,"tag":209,"props":2052,"children":2053},{"style":222},[2054],{"type":26,"value":1985},{"type":21,"tag":209,"props":2056,"children":2057},{"style":1988},[2058],{"type":26,"value":2059},"script",{"type":21,"tag":209,"props":2061,"children":2062},{"style":360},[2063],{"type":26,"value":2064}," lang",{"type":21,"tag":209,"props":2066,"children":2067},{"style":222},[2068],{"type":26,"value":1432},{"type":21,"tag":209,"props":2070,"children":2071},{"style":233},[2072],{"type":26,"value":2073},"\"js\"",{"type":21,"tag":209,"props":2075,"children":2076},{"style":222},[2077],{"type":26,"value":1996},{"type":21,"tag":209,"props":2079,"children":2080},{"class":211,"line":288},[2081,2085,2089,2093],{"type":21,"tag":209,"props":2082,"children":2083},{"style":216},[2084],{"type":26,"value":260},{"type":21,"tag":209,"props":2086,"children":2087},{"style":263},[2088],{"type":26,"value":266},{"type":21,"tag":209,"props":2090,"children":2091},{"style":216},[2092],{"type":26,"value":271},{"type":21,"tag":209,"props":2094,"children":2095},{"style":222},[2096],{"type":26,"value":276},{"type":21,"tag":209,"props":2098,"children":2099},{"class":211,"line":307},[2100],{"type":21,"tag":209,"props":2101,"children":2102},{"style":222},[2103],{"type":26,"value":285},{"type":21,"tag":209,"props":2105,"children":2106},{"class":211,"line":325},[2107,2111,2115],{"type":21,"tag":209,"props":2108,"children":2109},{"style":222},[2110],{"type":26,"value":294},{"type":21,"tag":209,"props":2112,"children":2113},{"style":233},[2114],{"type":26,"value":299},{"type":21,"tag":209,"props":2116,"children":2117},{"style":222},[2118],{"type":26,"value":304},{"type":21,"tag":209,"props":2120,"children":2121},{"class":211,"line":334},[2122,2126,2130],{"type":21,"tag":209,"props":2123,"children":2124},{"style":222},[2125],{"type":26,"value":313},{"type":21,"tag":209,"props":2127,"children":2128},{"style":233},[2129],{"type":26,"value":318},{"type":21,"tag":209,"props":2131,"children":2132},{"style":222},[2133],{"type":26,"value":304},{"type":21,"tag":209,"props":2135,"children":2136},{"class":211,"line":343},[2137],{"type":21,"tag":209,"props":2138,"children":2139},{"style":222},[2140],{"type":26,"value":331},{"type":21,"tag":209,"props":2142,"children":2143},{"class":211,"line":351},[2144],{"type":21,"tag":209,"props":2145,"children":2146},{"style":222},[2147],{"type":26,"value":340},{"type":21,"tag":209,"props":2149,"children":2150},{"class":211,"line":444},[2151],{"type":21,"tag":209,"props":2152,"children":2153},{"emptyLinePlaceholder":248},[2154],{"type":26,"value":251},{"type":21,"tag":209,"props":2156,"children":2157},{"class":211,"line":454},[2158,2162,2166],{"type":21,"tag":209,"props":2159,"children":2160},{"style":216},[2161],{"type":26,"value":1589},{"type":21,"tag":209,"props":2163,"children":2164},{"style":216},[2165],{"type":26,"value":1594},{"type":21,"tag":209,"props":2167,"children":2168},{"style":222},[2169],{"type":26,"value":276},{"type":21,"tag":209,"props":2171,"children":2172},{"class":211,"line":463},[2173,2178,2183],{"type":21,"tag":209,"props":2174,"children":2175},{"style":222},[2176],{"type":26,"value":2177},"    name: ",{"type":21,"tag":209,"props":2179,"children":2180},{"style":233},[2181],{"type":26,"value":2182},"\"VComponent\"",{"type":21,"tag":209,"props":2184,"children":2185},{"style":222},[2186],{"type":26,"value":304},{"type":21,"tag":209,"props":2188,"children":2189},{"class":211,"line":472},[2190],{"type":21,"tag":209,"props":2191,"children":2192},{"style":222},[2193],{"type":26,"value":2194},"    props:{\n",{"type":21,"tag":209,"props":2196,"children":2197},{"class":211,"line":480},[2198],{"type":21,"tag":209,"props":2199,"children":2200},{"style":222},[2201],{"type":26,"value":2202},"        vprop:{\n",{"type":21,"tag":209,"props":2204,"children":2205},{"class":211,"line":489},[2206],{"type":21,"tag":209,"props":2207,"children":2208},{"style":222},[2209],{"type":26,"value":2210},"            type:Boolean,\n",{"type":21,"tag":209,"props":2212,"children":2213},{"class":211,"line":847},[2214,2219,2224],{"type":21,"tag":209,"props":2215,"children":2216},{"style":222},[2217],{"type":26,"value":2218},"            default:",{"type":21,"tag":209,"props":2220,"children":2221},{"style":263},[2222],{"type":26,"value":2223},"true",{"type":21,"tag":209,"props":2225,"children":2226},{"style":222},[2227],{"type":26,"value":304},{"type":21,"tag":209,"props":2229,"children":2230},{"class":211,"line":860},[2231],{"type":21,"tag":209,"props":2232,"children":2233},{"style":222},[2234],{"type":26,"value":2235},"        }\n",{"type":21,"tag":209,"props":2237,"children":2238},{"class":211,"line":877},[2239],{"type":21,"tag":209,"props":2240,"children":2241},{"style":448},[2242],{"type":26,"value":2243},"        // ... Your Props ...\n",{"type":21,"tag":209,"props":2245,"children":2246},{"class":211,"line":889},[2247],{"type":21,"tag":209,"props":2248,"children":2249},{"style":222},[2250],{"type":26,"value":2251},"    },\n",{"type":21,"tag":209,"props":2253,"children":2254},{"class":211,"line":902},[2255],{"type":21,"tag":209,"props":2256,"children":2257},{"style":222},[2258],{"type":26,"value":2259},"    vent:{\n",{"type":21,"tag":209,"props":2261,"children":2262},{"class":211,"line":914},[2263],{"type":21,"tag":209,"props":2264,"children":2265},{"style":448},[2266],{"type":26,"value":2267},"        // Indirect binding - the named function within this component will be bound.\n",{"type":21,"tag":209,"props":2269,"children":2270},{"class":211,"line":922},[2271,2276,2280,2284,2288,2292,2296,2301,2306],{"type":21,"tag":209,"props":2272,"children":2273},{"style":222},[2274],{"type":26,"value":2275},"        [",{"type":21,"tag":209,"props":2277,"children":2278},{"style":263},[2279],{"type":26,"value":373},{"type":21,"tag":209,"props":2281,"children":2282},{"style":222},[2283],{"type":26,"value":378},{"type":21,"tag":209,"props":2285,"children":2286},{"style":263},[2287],{"type":26,"value":383},{"type":21,"tag":209,"props":2289,"children":2290},{"style":222},[2291],{"type":26,"value":378},{"type":21,"tag":209,"props":2293,"children":2294},{"style":263},[2295],{"type":26,"value":392},{"type":21,"tag":209,"props":2297,"children":2298},{"style":222},[2299],{"type":26,"value":2300},"]:",{"type":21,"tag":209,"props":2302,"children":2303},{"style":233},[2304],{"type":26,"value":2305},"'recalcPoints'",{"type":21,"tag":209,"props":2307,"children":2308},{"style":222},[2309],{"type":26,"value":304},{"type":21,"tag":209,"props":2311,"children":2313},{"class":211,"line":2312},24,[2314],{"type":21,"tag":209,"props":2315,"children":2316},{"style":448},[2317],{"type":26,"value":2318},"        // Direct binding - this function will be bound.\n",{"type":21,"tag":209,"props":2320,"children":2322},{"class":211,"line":2321},25,[2323,2327,2331,2335,2339,2343,2348,2353,2357,2361,2365],{"type":21,"tag":209,"props":2324,"children":2325},{"style":222},[2326],{"type":26,"value":2275},{"type":21,"tag":209,"props":2328,"children":2329},{"style":263},[2330],{"type":26,"value":373},{"type":21,"tag":209,"props":2332,"children":2333},{"style":222},[2334],{"type":26,"value":378},{"type":21,"tag":209,"props":2336,"children":2337},{"style":263},[2338],{"type":26,"value":383},{"type":21,"tag":209,"props":2340,"children":2341},{"style":222},[2342],{"type":26,"value":378},{"type":21,"tag":209,"props":2344,"children":2345},{"style":263},[2346],{"type":26,"value":2347},"END",{"type":21,"tag":209,"props":2349,"children":2350},{"style":222},[2351],{"type":26,"value":2352},"](",{"type":21,"tag":209,"props":2354,"children":2355},{"style":400},[2356],{"type":26,"value":403},{"type":21,"tag":209,"props":2358,"children":2359},{"style":222},[2360],{"type":26,"value":408},{"type":21,"tag":209,"props":2362,"children":2363},{"style":400},[2364],{"type":26,"value":413},{"type":21,"tag":209,"props":2366,"children":2367},{"style":222},[2368],{"type":26,"value":2369},"){\n",{"type":21,"tag":209,"props":2371,"children":2373},{"class":211,"line":2372},26,[2374],{"type":21,"tag":209,"props":2375,"children":2376},{"style":448},[2377],{"type":26,"value":2378},"            // Called whenever the `EVENTS.PLAYER.END` event is triggered or requested.\n",{"type":21,"tag":209,"props":2380,"children":2382},{"class":211,"line":2381},27,[2383],{"type":21,"tag":209,"props":2384,"children":2385},{"style":222},[2386],{"type":26,"value":2235},{"type":21,"tag":209,"props":2388,"children":2390},{"class":211,"line":2389},28,[2391],{"type":21,"tag":209,"props":2392,"children":2393},{"style":222},[2394],{"type":26,"value":2251},{"type":21,"tag":209,"props":2396,"children":2398},{"class":211,"line":2397},29,[2399],{"type":21,"tag":209,"props":2400,"children":2401},{"style":222},[2402],{"type":26,"value":2403},"    methods:{\n",{"type":21,"tag":209,"props":2405,"children":2407},{"class":211,"line":2406},30,[2408],{"type":21,"tag":209,"props":2409,"children":2410},{"style":448},[2411],{"type":26,"value":2412},"        /**\n",{"type":21,"tag":209,"props":2414,"children":2416},{"class":211,"line":2415},31,[2417],{"type":21,"tag":209,"props":2418,"children":2419},{"style":448},[2420],{"type":26,"value":2421},"         * This method will be called whenever the `EVENTS.PLAYER.START` event is\n",{"type":21,"tag":209,"props":2423,"children":2425},{"class":211,"line":2424},32,[2426],{"type":21,"tag":209,"props":2427,"children":2428},{"style":448},[2429],{"type":26,"value":2430},"         * triggered or requested.\n",{"type":21,"tag":209,"props":2432,"children":2434},{"class":211,"line":2433},33,[2435],{"type":21,"tag":209,"props":2436,"children":2437},{"style":448},[2438],{"type":26,"value":2439},"         */\n",{"type":21,"tag":209,"props":2441,"children":2443},{"class":211,"line":2442},34,[2444,2449,2453,2457,2461,2465],{"type":21,"tag":209,"props":2445,"children":2446},{"style":360},[2447],{"type":26,"value":2448},"        recalcPoints",{"type":21,"tag":209,"props":2450,"children":2451},{"style":222},[2452],{"type":26,"value":368},{"type":21,"tag":209,"props":2454,"children":2455},{"style":400},[2456],{"type":26,"value":403},{"type":21,"tag":209,"props":2458,"children":2459},{"style":222},[2460],{"type":26,"value":408},{"type":21,"tag":209,"props":2462,"children":2463},{"style":400},[2464],{"type":26,"value":413},{"type":21,"tag":209,"props":2466,"children":2467},{"style":222},[2468],{"type":26,"value":2369},{"type":21,"tag":209,"props":2470,"children":2472},{"class":211,"line":2471},35,[2473],{"type":21,"tag":209,"props":2474,"children":2475},{"style":448},[2476],{"type":26,"value":2477},"            // Because the `vent` events are bound to the component, you can use\n",{"type":21,"tag":209,"props":2479,"children":2481},{"class":211,"line":2480},36,[2482],{"type":21,"tag":209,"props":2483,"children":2484},{"style":448},[2485],{"type":26,"value":2486},"            // this to get props, data, computed, etc. of the component.\n",{"type":21,"tag":209,"props":2488,"children":2490},{"class":211,"line":2489},37,[2491,2496,2500,2504,2509],{"type":21,"tag":209,"props":2492,"children":2493},{"style":222},[2494],{"type":26,"value":2495},"            console.",{"type":21,"tag":209,"props":2497,"children":2498},{"style":360},[2499],{"type":26,"value":1059},{"type":21,"tag":209,"props":2501,"children":2502},{"style":222},[2503],{"type":26,"value":368},{"type":21,"tag":209,"props":2505,"children":2506},{"style":263},[2507],{"type":26,"value":2508},"this",{"type":21,"tag":209,"props":2510,"children":2511},{"style":222},[2512],{"type":26,"value":2513},".vprop);\n",{"type":21,"tag":209,"props":2515,"children":2517},{"class":211,"line":2516},38,[2518],{"type":21,"tag":209,"props":2519,"children":2520},{"style":222},[2521],{"type":26,"value":2522},"        },\n",{"type":21,"tag":209,"props":2524,"children":2526},{"class":211,"line":2525},39,[2527],{"type":21,"tag":209,"props":2528,"children":2529},{"style":448},[2530],{"type":26,"value":2412},{"type":21,"tag":209,"props":2532,"children":2534},{"class":211,"line":2533},40,[2535],{"type":21,"tag":209,"props":2536,"children":2537},{"style":448},[2538],{"type":26,"value":2539},"         * Trigger an event as a result of doing something.\n",{"type":21,"tag":209,"props":2541,"children":2543},{"class":211,"line":2542},41,[2544],{"type":21,"tag":209,"props":2545,"children":2546},{"style":448},[2547],{"type":26,"value":2439},{"type":21,"tag":209,"props":2549,"children":2551},{"class":211,"line":2550},42,[2552,2557],{"type":21,"tag":209,"props":2553,"children":2554},{"style":360},[2555],{"type":26,"value":2556},"        doSomething",{"type":21,"tag":209,"props":2558,"children":2559},{"style":222},[2560],{"type":26,"value":2561},"(){\n",{"type":21,"tag":209,"props":2563,"children":2565},{"class":211,"line":2564},43,[2566,2571,2576,2580,2584,2588,2592,2596,2600,2604],{"type":21,"tag":209,"props":2567,"children":2568},{"style":263},[2569],{"type":26,"value":2570},"            this",{"type":21,"tag":209,"props":2572,"children":2573},{"style":222},[2574],{"type":26,"value":2575},".$vent.",{"type":21,"tag":209,"props":2577,"children":2578},{"style":360},[2579],{"type":26,"value":499},{"type":21,"tag":209,"props":2581,"children":2582},{"style":222},[2583],{"type":26,"value":368},{"type":21,"tag":209,"props":2585,"children":2586},{"style":263},[2587],{"type":26,"value":373},{"type":21,"tag":209,"props":2589,"children":2590},{"style":222},[2591],{"type":26,"value":378},{"type":21,"tag":209,"props":2593,"children":2594},{"style":263},[2595],{"type":26,"value":383},{"type":21,"tag":209,"props":2597,"children":2598},{"style":222},[2599],{"type":26,"value":378},{"type":21,"tag":209,"props":2601,"children":2602},{"style":263},[2603],{"type":26,"value":2347},{"type":21,"tag":209,"props":2605,"children":2606},{"style":222},[2607],{"type":26,"value":2608},");\n",{"type":21,"tag":209,"props":2610,"children":2612},{"class":211,"line":2611},44,[2613],{"type":21,"tag":209,"props":2614,"children":2615},{"style":222},[2616],{"type":26,"value":2522},{"type":21,"tag":209,"props":2618,"children":2620},{"class":211,"line":2619},45,[2621],{"type":21,"tag":209,"props":2622,"children":2623},{"style":448},[2624],{"type":26,"value":2412},{"type":21,"tag":209,"props":2626,"children":2628},{"class":211,"line":2627},46,[2629],{"type":21,"tag":209,"props":2630,"children":2631},{"style":448},[2632],{"type":26,"value":2633},"         * Request replies from subscribers.\n",{"type":21,"tag":209,"props":2635,"children":2637},{"class":211,"line":2636},47,[2638],{"type":21,"tag":209,"props":2639,"children":2640},{"style":448},[2641],{"type":26,"value":2439},{"type":21,"tag":209,"props":2643,"children":2645},{"class":211,"line":2644},48,[2646,2651],{"type":21,"tag":209,"props":2647,"children":2648},{"style":360},[2649],{"type":26,"value":2650},"        getSomething",{"type":21,"tag":209,"props":2652,"children":2653},{"style":222},[2654],{"type":26,"value":2561},{"type":21,"tag":209,"props":2656,"children":2658},{"class":211,"line":2657},49,[2659,2663,2667,2671,2675,2679,2683,2687,2691,2695,2700,2705,2710,2714,2718,2722],{"type":21,"tag":209,"props":2660,"children":2661},{"style":263},[2662],{"type":26,"value":2570},{"type":21,"tag":209,"props":2664,"children":2665},{"style":222},[2666],{"type":26,"value":2575},{"type":21,"tag":209,"props":2668,"children":2669},{"style":360},[2670],{"type":26,"value":1343},{"type":21,"tag":209,"props":2672,"children":2673},{"style":222},[2674],{"type":26,"value":368},{"type":21,"tag":209,"props":2676,"children":2677},{"style":263},[2678],{"type":26,"value":373},{"type":21,"tag":209,"props":2680,"children":2681},{"style":222},[2682],{"type":26,"value":378},{"type":21,"tag":209,"props":2684,"children":2685},{"style":263},[2686],{"type":26,"value":383},{"type":21,"tag":209,"props":2688,"children":2689},{"style":222},[2690],{"type":26,"value":378},{"type":21,"tag":209,"props":2692,"children":2693},{"style":263},[2694],{"type":26,"value":2347},{"type":21,"tag":209,"props":2696,"children":2697},{"style":222},[2698],{"type":26,"value":2699},").",{"type":21,"tag":209,"props":2701,"children":2702},{"style":360},[2703],{"type":26,"value":2704},"then",{"type":21,"tag":209,"props":2706,"children":2707},{"style":222},[2708],{"type":26,"value":2709},"((",{"type":21,"tag":209,"props":2711,"children":2712},{"style":400},[2713],{"type":26,"value":1385},{"type":21,"tag":209,"props":2715,"children":2716},{"style":222},[2717],{"type":26,"value":432},{"type":21,"tag":209,"props":2719,"children":2720},{"style":216},[2721],{"type":26,"value":437},{"type":21,"tag":209,"props":2723,"children":2724},{"style":222},[2725],{"type":26,"value":276},{"type":21,"tag":209,"props":2727,"children":2729},{"class":211,"line":2728},50,[2730,2735,2739,2744,2748,2752],{"type":21,"tag":209,"props":2731,"children":2732},{"style":216},[2733],{"type":26,"value":2734},"                const",{"type":21,"tag":209,"props":2736,"children":2737},{"style":222},[2738],{"type":26,"value":1417},{"type":21,"tag":209,"props":2740,"children":2741},{"style":263},[2742],{"type":26,"value":2743},"resp",{"type":21,"tag":209,"props":2745,"children":2746},{"style":222},[2747],{"type":26,"value":1427},{"type":21,"tag":209,"props":2749,"children":2750},{"style":216},[2751],{"type":26,"value":1432},{"type":21,"tag":209,"props":2753,"children":2754},{"style":222},[2755],{"type":26,"value":1442},{"type":21,"tag":209,"props":2757,"children":2759},{"class":211,"line":2758},51,[2760,2765,2769],{"type":21,"tag":209,"props":2761,"children":2762},{"style":222},[2763],{"type":26,"value":2764},"                console.",{"type":21,"tag":209,"props":2766,"children":2767},{"style":360},[2768],{"type":26,"value":1059},{"type":21,"tag":209,"props":2770,"children":2771},{"style":222},[2772],{"type":26,"value":2773},"(resp);\n",{"type":21,"tag":209,"props":2775,"children":2777},{"class":211,"line":2776},52,[2778],{"type":21,"tag":209,"props":2779,"children":2780},{"style":222},[2781],{"type":26,"value":2782},"            });\n",{"type":21,"tag":209,"props":2784,"children":2786},{"class":211,"line":2785},53,[2787],{"type":21,"tag":209,"props":2788,"children":2789},{"style":222},[2790],{"type":26,"value":2522},{"type":21,"tag":209,"props":2792,"children":2794},{"class":211,"line":2793},54,[2795],{"type":21,"tag":209,"props":2796,"children":2797},{"style":222},[2798],{"type":26,"value":2251},{"type":21,"tag":209,"props":2800,"children":2802},{"class":211,"line":2801},55,[2803],{"type":21,"tag":209,"props":2804,"children":2805},{"style":222},[2806],{"type":26,"value":340},{"type":21,"tag":209,"props":2808,"children":2810},{"class":211,"line":2809},56,[2811,2815,2819],{"type":21,"tag":209,"props":2812,"children":2813},{"style":222},[2814],{"type":26,"value":2024},{"type":21,"tag":209,"props":2816,"children":2817},{"style":1988},[2818],{"type":26,"value":2059},{"type":21,"tag":209,"props":2820,"children":2821},{"style":222},[2822],{"type":26,"value":1996},{"type":21,"tag":22,"props":2824,"children":2825},{},[2826,2828,2833,2835,2841,2843,2849,2851,2856,2858,2864,2865,2870],{"type":26,"value":2827},"All events specified in the ",{"type":21,"tag":63,"props":2829,"children":2831},{"className":2830},[],[2832],{"type":26,"value":1912},{"type":26,"value":2834}," object are bound to the context of the component on ",{"type":21,"tag":63,"props":2836,"children":2838},{"className":2837},[],[2839],{"type":26,"value":2840},"mounted",{"type":26,"value":2842},", and unbound during ",{"type":21,"tag":63,"props":2844,"children":2846},{"className":2845},[],[2847],{"type":26,"value":2848},"beforeUnmount",{"type":26,"value":2850},". This means that you can use ",{"type":21,"tag":63,"props":2852,"children":2854},{"className":2853},[],[2855],{"type":26,"value":2508},{"type":26,"value":2857}," to refer to the context of the component within these functions and access ",{"type":21,"tag":63,"props":2859,"children":2861},{"className":2860},[],[2862],{"type":26,"value":2863},"data",{"type":26,"value":408},{"type":21,"tag":63,"props":2866,"children":2868},{"className":2867},[],[2869],{"type":26,"value":76},{"type":26,"value":2871},", computed properties, etc.; and that the listeners will be safely bound and unbound automagically for you without any need to manually subscribe or unsubscribe.",{"type":21,"tag":193,"props":2873,"children":2875},{"id":2874},"composition-api",[2876],{"type":26,"value":189},{"type":21,"tag":22,"props":2878,"children":2879},{},[2880,2882,2888],{"type":26,"value":2881},"Using VPubSub with the Composition API is similar to using it outside of Vue, and can be used in a ",{"type":21,"tag":63,"props":2883,"children":2885},{"className":2884},[],[2886],{"type":26,"value":2887},"setup",{"type":26,"value":2889}," script tag in single-file components.",{"type":21,"tag":200,"props":2891,"children":2893},{"className":1972,"code":2892,"language":13,"meta":8,"style":8},"\u003Cscript setup>\n    import {vent} from \"vpubsub\";\n    import EVENTS from \"events\";\n    \n    function onStart(arg1, arg2){\n        // Do something on player start.\n    }\n    function onStartRequest(arg1, arg2){\n        // Return something player start request.\n        return 42;\n    }\n    \n    vent.on(EVENTS.PLAYER.START, onStart);\n    vent.on(EVENTS.PLAYER.START, onStartRequest);\n    \n    vent.trigger(EVENTS.PLAYER.START, 1, 2);\n    vent.request(EVENTS.PLAYER.START, 1, 2).then(async(res) => {\n        const [res1, res2] = await res;\n        console.log(res1, res2);\n    });\n\u003C/script>\n",[2894],{"type":21,"tag":63,"props":2895,"children":2896},{"__ignoreMap":8},[2897,2917,2941,2966,2974,3007,3015,3022,3054,3062,3079,3086,3093,3134,3174,3181,3238,3325,3367,3384,3392],{"type":21,"tag":209,"props":2898,"children":2899},{"class":211,"line":212},[2900,2904,2908,2913],{"type":21,"tag":209,"props":2901,"children":2902},{"style":222},[2903],{"type":26,"value":1985},{"type":21,"tag":209,"props":2905,"children":2906},{"style":1988},[2907],{"type":26,"value":2059},{"type":21,"tag":209,"props":2909,"children":2910},{"style":360},[2911],{"type":26,"value":2912}," setup",{"type":21,"tag":209,"props":2914,"children":2915},{"style":222},[2916],{"type":26,"value":1996},{"type":21,"tag":209,"props":2918,"children":2919},{"class":211,"line":244},[2920,2925,2929,2933,2937],{"type":21,"tag":209,"props":2921,"children":2922},{"style":216},[2923],{"type":26,"value":2924},"    import",{"type":21,"tag":209,"props":2926,"children":2927},{"style":222},[2928],{"type":26,"value":225},{"type":21,"tag":209,"props":2930,"children":2931},{"style":216},[2932],{"type":26,"value":230},{"type":21,"tag":209,"props":2934,"children":2935},{"style":233},[2936],{"type":26,"value":236},{"type":21,"tag":209,"props":2938,"children":2939},{"style":222},[2940],{"type":26,"value":241},{"type":21,"tag":209,"props":2942,"children":2943},{"class":211,"line":254},[2944,2948,2953,2957,2962],{"type":21,"tag":209,"props":2945,"children":2946},{"style":216},[2947],{"type":26,"value":2924},{"type":21,"tag":209,"props":2949,"children":2950},{"style":222},[2951],{"type":26,"value":2952}," EVENTS ",{"type":21,"tag":209,"props":2954,"children":2955},{"style":216},[2956],{"type":26,"value":230},{"type":21,"tag":209,"props":2958,"children":2959},{"style":233},[2960],{"type":26,"value":2961}," \"events\"",{"type":21,"tag":209,"props":2963,"children":2964},{"style":222},[2965],{"type":26,"value":241},{"type":21,"tag":209,"props":2967,"children":2968},{"class":211,"line":279},[2969],{"type":21,"tag":209,"props":2970,"children":2971},{"style":222},[2972],{"type":26,"value":2973},"    \n",{"type":21,"tag":209,"props":2975,"children":2976},{"class":211,"line":288},[2977,2982,2987,2991,2995,2999,3003],{"type":21,"tag":209,"props":2978,"children":2979},{"style":216},[2980],{"type":26,"value":2981},"    function",{"type":21,"tag":209,"props":2983,"children":2984},{"style":360},[2985],{"type":26,"value":2986}," onStart",{"type":21,"tag":209,"props":2988,"children":2989},{"style":222},[2990],{"type":26,"value":368},{"type":21,"tag":209,"props":2992,"children":2993},{"style":400},[2994],{"type":26,"value":403},{"type":21,"tag":209,"props":2996,"children":2997},{"style":222},[2998],{"type":26,"value":408},{"type":21,"tag":209,"props":3000,"children":3001},{"style":400},[3002],{"type":26,"value":413},{"type":21,"tag":209,"props":3004,"children":3005},{"style":222},[3006],{"type":26,"value":2369},{"type":21,"tag":209,"props":3008,"children":3009},{"class":211,"line":307},[3010],{"type":21,"tag":209,"props":3011,"children":3012},{"style":448},[3013],{"type":26,"value":3014},"        // Do something on player start.\n",{"type":21,"tag":209,"props":3016,"children":3017},{"class":211,"line":325},[3018],{"type":21,"tag":209,"props":3019,"children":3020},{"style":222},[3021],{"type":26,"value":331},{"type":21,"tag":209,"props":3023,"children":3024},{"class":211,"line":334},[3025,3029,3034,3038,3042,3046,3050],{"type":21,"tag":209,"props":3026,"children":3027},{"style":216},[3028],{"type":26,"value":2981},{"type":21,"tag":209,"props":3030,"children":3031},{"style":360},[3032],{"type":26,"value":3033}," onStartRequest",{"type":21,"tag":209,"props":3035,"children":3036},{"style":222},[3037],{"type":26,"value":368},{"type":21,"tag":209,"props":3039,"children":3040},{"style":400},[3041],{"type":26,"value":403},{"type":21,"tag":209,"props":3043,"children":3044},{"style":222},[3045],{"type":26,"value":408},{"type":21,"tag":209,"props":3047,"children":3048},{"style":400},[3049],{"type":26,"value":413},{"type":21,"tag":209,"props":3051,"children":3052},{"style":222},[3053],{"type":26,"value":2369},{"type":21,"tag":209,"props":3055,"children":3056},{"class":211,"line":343},[3057],{"type":21,"tag":209,"props":3058,"children":3059},{"style":448},[3060],{"type":26,"value":3061},"        // Return something player start request.\n",{"type":21,"tag":209,"props":3063,"children":3064},{"class":211,"line":351},[3065,3070,3075],{"type":21,"tag":209,"props":3066,"children":3067},{"style":216},[3068],{"type":26,"value":3069},"        return",{"type":21,"tag":209,"props":3071,"children":3072},{"style":263},[3073],{"type":26,"value":3074}," 42",{"type":21,"tag":209,"props":3076,"children":3077},{"style":222},[3078],{"type":26,"value":241},{"type":21,"tag":209,"props":3080,"children":3081},{"class":211,"line":444},[3082],{"type":21,"tag":209,"props":3083,"children":3084},{"style":222},[3085],{"type":26,"value":331},{"type":21,"tag":209,"props":3087,"children":3088},{"class":211,"line":454},[3089],{"type":21,"tag":209,"props":3090,"children":3091},{"style":222},[3092],{"type":26,"value":2973},{"type":21,"tag":209,"props":3094,"children":3095},{"class":211,"line":463},[3096,3101,3105,3109,3113,3117,3121,3125,3129],{"type":21,"tag":209,"props":3097,"children":3098},{"style":222},[3099],{"type":26,"value":3100},"    vent.",{"type":21,"tag":209,"props":3102,"children":3103},{"style":360},[3104],{"type":26,"value":363},{"type":21,"tag":209,"props":3106,"children":3107},{"style":222},[3108],{"type":26,"value":368},{"type":21,"tag":209,"props":3110,"children":3111},{"style":263},[3112],{"type":26,"value":373},{"type":21,"tag":209,"props":3114,"children":3115},{"style":222},[3116],{"type":26,"value":378},{"type":21,"tag":209,"props":3118,"children":3119},{"style":263},[3120],{"type":26,"value":383},{"type":21,"tag":209,"props":3122,"children":3123},{"style":222},[3124],{"type":26,"value":378},{"type":21,"tag":209,"props":3126,"children":3127},{"style":263},[3128],{"type":26,"value":392},{"type":21,"tag":209,"props":3130,"children":3131},{"style":222},[3132],{"type":26,"value":3133},", onStart);\n",{"type":21,"tag":209,"props":3135,"children":3136},{"class":211,"line":472},[3137,3141,3145,3149,3153,3157,3161,3165,3169],{"type":21,"tag":209,"props":3138,"children":3139},{"style":222},[3140],{"type":26,"value":3100},{"type":21,"tag":209,"props":3142,"children":3143},{"style":360},[3144],{"type":26,"value":363},{"type":21,"tag":209,"props":3146,"children":3147},{"style":222},[3148],{"type":26,"value":368},{"type":21,"tag":209,"props":3150,"children":3151},{"style":263},[3152],{"type":26,"value":373},{"type":21,"tag":209,"props":3154,"children":3155},{"style":222},[3156],{"type":26,"value":378},{"type":21,"tag":209,"props":3158,"children":3159},{"style":263},[3160],{"type":26,"value":383},{"type":21,"tag":209,"props":3162,"children":3163},{"style":222},[3164],{"type":26,"value":378},{"type":21,"tag":209,"props":3166,"children":3167},{"style":263},[3168],{"type":26,"value":392},{"type":21,"tag":209,"props":3170,"children":3171},{"style":222},[3172],{"type":26,"value":3173},", onStartRequest);\n",{"type":21,"tag":209,"props":3175,"children":3176},{"class":211,"line":480},[3177],{"type":21,"tag":209,"props":3178,"children":3179},{"style":222},[3180],{"type":26,"value":2973},{"type":21,"tag":209,"props":3182,"children":3183},{"class":211,"line":489},[3184,3188,3192,3196,3200,3204,3208,3212,3216,3220,3225,3229,3234],{"type":21,"tag":209,"props":3185,"children":3186},{"style":222},[3187],{"type":26,"value":3100},{"type":21,"tag":209,"props":3189,"children":3190},{"style":360},[3191],{"type":26,"value":499},{"type":21,"tag":209,"props":3193,"children":3194},{"style":222},[3195],{"type":26,"value":368},{"type":21,"tag":209,"props":3197,"children":3198},{"style":263},[3199],{"type":26,"value":373},{"type":21,"tag":209,"props":3201,"children":3202},{"style":222},[3203],{"type":26,"value":378},{"type":21,"tag":209,"props":3205,"children":3206},{"style":263},[3207],{"type":26,"value":383},{"type":21,"tag":209,"props":3209,"children":3210},{"style":222},[3211],{"type":26,"value":378},{"type":21,"tag":209,"props":3213,"children":3214},{"style":263},[3215],{"type":26,"value":392},{"type":21,"tag":209,"props":3217,"children":3218},{"style":222},[3219],{"type":26,"value":408},{"type":21,"tag":209,"props":3221,"children":3222},{"style":263},[3223],{"type":26,"value":3224},"1",{"type":21,"tag":209,"props":3226,"children":3227},{"style":222},[3228],{"type":26,"value":408},{"type":21,"tag":209,"props":3230,"children":3231},{"style":263},[3232],{"type":26,"value":3233},"2",{"type":21,"tag":209,"props":3235,"children":3236},{"style":222},[3237],{"type":26,"value":2608},{"type":21,"tag":209,"props":3239,"children":3240},{"class":211,"line":847},[3241,3245,3249,3253,3257,3261,3265,3269,3273,3277,3281,3285,3289,3293,3297,3301,3305,3309,3313,3317,3321],{"type":21,"tag":209,"props":3242,"children":3243},{"style":222},[3244],{"type":26,"value":3100},{"type":21,"tag":209,"props":3246,"children":3247},{"style":360},[3248],{"type":26,"value":1343},{"type":21,"tag":209,"props":3250,"children":3251},{"style":222},[3252],{"type":26,"value":368},{"type":21,"tag":209,"props":3254,"children":3255},{"style":263},[3256],{"type":26,"value":373},{"type":21,"tag":209,"props":3258,"children":3259},{"style":222},[3260],{"type":26,"value":378},{"type":21,"tag":209,"props":3262,"children":3263},{"style":263},[3264],{"type":26,"value":383},{"type":21,"tag":209,"props":3266,"children":3267},{"style":222},[3268],{"type":26,"value":378},{"type":21,"tag":209,"props":3270,"children":3271},{"style":263},[3272],{"type":26,"value":392},{"type":21,"tag":209,"props":3274,"children":3275},{"style":222},[3276],{"type":26,"value":408},{"type":21,"tag":209,"props":3278,"children":3279},{"style":263},[3280],{"type":26,"value":3224},{"type":21,"tag":209,"props":3282,"children":3283},{"style":222},[3284],{"type":26,"value":408},{"type":21,"tag":209,"props":3286,"children":3287},{"style":263},[3288],{"type":26,"value":3233},{"type":21,"tag":209,"props":3290,"children":3291},{"style":222},[3292],{"type":26,"value":2699},{"type":21,"tag":209,"props":3294,"children":3295},{"style":360},[3296],{"type":26,"value":2704},{"type":21,"tag":209,"props":3298,"children":3299},{"style":222},[3300],{"type":26,"value":368},{"type":21,"tag":209,"props":3302,"children":3303},{"style":216},[3304],{"type":26,"value":1376},{"type":21,"tag":209,"props":3306,"children":3307},{"style":222},[3308],{"type":26,"value":368},{"type":21,"tag":209,"props":3310,"children":3311},{"style":400},[3312],{"type":26,"value":1385},{"type":21,"tag":209,"props":3314,"children":3315},{"style":222},[3316],{"type":26,"value":432},{"type":21,"tag":209,"props":3318,"children":3319},{"style":216},[3320],{"type":26,"value":437},{"type":21,"tag":209,"props":3322,"children":3323},{"style":222},[3324],{"type":26,"value":276},{"type":21,"tag":209,"props":3326,"children":3327},{"class":211,"line":860},[3328,3333,3337,3342,3346,3351,3355,3359,3363],{"type":21,"tag":209,"props":3329,"children":3330},{"style":216},[3331],{"type":26,"value":3332},"        const",{"type":21,"tag":209,"props":3334,"children":3335},{"style":222},[3336],{"type":26,"value":1417},{"type":21,"tag":209,"props":3338,"children":3339},{"style":263},[3340],{"type":26,"value":3341},"res1",{"type":21,"tag":209,"props":3343,"children":3344},{"style":222},[3345],{"type":26,"value":408},{"type":21,"tag":209,"props":3347,"children":3348},{"style":263},[3349],{"type":26,"value":3350},"res2",{"type":21,"tag":209,"props":3352,"children":3353},{"style":222},[3354],{"type":26,"value":1427},{"type":21,"tag":209,"props":3356,"children":3357},{"style":216},[3358],{"type":26,"value":1432},{"type":21,"tag":209,"props":3360,"children":3361},{"style":216},[3362],{"type":26,"value":1437},{"type":21,"tag":209,"props":3364,"children":3365},{"style":222},[3366],{"type":26,"value":1442},{"type":21,"tag":209,"props":3368,"children":3369},{"class":211,"line":877},[3370,3375,3379],{"type":21,"tag":209,"props":3371,"children":3372},{"style":222},[3373],{"type":26,"value":3374},"        console.",{"type":21,"tag":209,"props":3376,"children":3377},{"style":360},[3378],{"type":26,"value":1059},{"type":21,"tag":209,"props":3380,"children":3381},{"style":222},[3382],{"type":26,"value":3383},"(res1, res2);\n",{"type":21,"tag":209,"props":3385,"children":3386},{"class":211,"line":889},[3387],{"type":21,"tag":209,"props":3388,"children":3389},{"style":222},[3390],{"type":26,"value":3391},"    });\n",{"type":21,"tag":209,"props":3393,"children":3394},{"class":211,"line":902},[3395,3399,3403],{"type":21,"tag":209,"props":3396,"children":3397},{"style":222},[3398],{"type":26,"value":2024},{"type":21,"tag":209,"props":3400,"children":3401},{"style":1988},[3402],{"type":26,"value":2059},{"type":21,"tag":209,"props":3404,"children":3405},{"style":222},[3406],{"type":26,"value":1996},{"type":21,"tag":193,"props":3408,"children":3410},{"id":3409},"what-are-my-import-options",[3411],{"type":26,"value":3412},"What are my import options?",{"type":21,"tag":22,"props":3414,"children":3415},{},[3416,3418,3424,3426,3432,3434,3440,3442,3447,3449,3454],{"type":26,"value":3417},"As for imports, you can choose between importing from ",{"type":21,"tag":63,"props":3419,"children":3421},{"className":3420},[],[3422],{"type":26,"value":3423},"vpubsub",{"type":26,"value":3425},", which expects ",{"type":21,"tag":63,"props":3427,"children":3429},{"className":3428},[],[3430],{"type":26,"value":3431},"lodash-es",{"type":26,"value":3433}," as a peer dependency but doesn't bake in the parts it needs; or you can import from ",{"type":21,"tag":63,"props":3435,"children":3437},{"className":3436},[],[3438],{"type":26,"value":3439},"vpubsub/dist/vpubsub.full.js",{"type":26,"value":3441}," which bakes in just those bits of ",{"type":21,"tag":63,"props":3443,"children":3445},{"className":3444},[],[3446],{"type":26,"value":3431},{"type":26,"value":3448}," that it relies on, and is suitable if you don't intend to make ",{"type":21,"tag":63,"props":3450,"children":3452},{"className":3451},[],[3453],{"type":26,"value":3431},{"type":26,"value":3455}," part of your project.",{"type":21,"tag":193,"props":3457,"children":3459},{"id":3458},"this-is-pretty-neat-id-like-to-use-it-in-my-project",[3460],{"type":26,"value":3461},"This is pretty neat! I'd like to use it in my project.",{"type":21,"tag":22,"props":3463,"children":3464},{},[3465],{"type":26,"value":3466},"Go for it. 🚀",{"type":21,"tag":22,"props":3468,"children":3469},{},[3470,3472,3479,3481,3488],{"type":26,"value":3471},"You can find it over on ",{"type":21,"tag":29,"props":3473,"children":3476},{"href":3474,"rel":3475},"https://github.com/SaneMethod/vpubsub",[93],[3477],{"type":26,"value":3478},"github",{"type":26,"value":3480}," - license details are ",{"type":21,"tag":29,"props":3482,"children":3485},{"href":3483,"rel":3484},"https://github.com/SaneMethod/vpubsub/blob/master/LICENSE.txt",[93],[3486],{"type":26,"value":3487},"in the repo",{"type":26,"value":378},{"type":21,"tag":3490,"props":3491,"children":3492},"style",{},[3493],{"type":26,"value":3494},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":8,"searchDepth":254,"depth":254,"links":3496},[3497,3498,3504],{"id":53,"depth":254,"text":56},{"id":165,"depth":254,"text":168,"children":3499},[3500,3501,3502,3503],{"id":195,"depth":279,"text":198},{"id":585,"depth":279,"text":588},{"id":930,"depth":279,"text":933},{"id":1074,"depth":279,"text":1077},{"id":1487,"depth":254,"text":1490,"children":3505},[3506,3507,3508,3509,3510],{"id":1498,"depth":279,"text":1501},{"id":1899,"depth":279,"text":180},{"id":2874,"depth":279,"text":189},{"id":3409,"depth":279,"text":3412},{"id":3458,"depth":279,"text":3461},"markdown","content:ckeefer:2024-7:VPubSub.md","content","ckeefer/2024-7/VPubSub.md","ckeefer/2024-7/VPubSub","md",{"user":3518,"name":3519},"ckeefer","Christopher Keefer",{"_path":3521,"_dir":3522,"_draft":7,"_partial":7,"_locale":8,"title":3523,"description":3524,"tags":3525,"publishDate":3529,"excerpt":3524,"image":3530,"body":3531,"_type":3511,"_id":4267,"_source":3513,"_file":4268,"_stem":4269,"_extension":3516,"author":4270},"/phendry/2023-11-06/frontendframeworksin2024","2023-11-06","Frontend Frameworks in 2024: React, Svelte and Vue","Several years ago, Art+Logic settled on Vue.js as our preferred frontend Web framework. Now, in 2024, we feel it's time to revisit the frontend framework landscape to see how things have (or haven't) changed.",[3526,3527,3528,13],"programming","react","svelte","2024-05-15","/phendry/2023-11-06/img/frontend_frameworks_2024.png",{"type":18,"children":3532,"toc":4256},[3533,3556,3578,3601,3606,3611,3616,3661,3693,3698,3705,3710,3715,3720,3751,3756,3761,3766,3794,3808,3813,3822,3827,3841,3860,3865,3870,3875,3880,3894,3902,3907,3912,3917,3922,3934,3965,3971,3976,3998,4003,4009,4014,4019,4025,4030,4035,4040,4045,4051,4056,4246,4251],{"type":21,"tag":22,"props":3534,"children":3535},{},[3536,3538,3545,3547,3554],{"type":26,"value":3537},"Several years ago, Art+Logic settled on ",{"type":21,"tag":29,"props":3539,"children":3542},{"href":3540,"rel":3541},"https://vuejs.org/",[93],[3543],{"type":26,"value":3544},"Vue.js",{"type":26,"value":3546}," as our ",{"type":21,"tag":29,"props":3548,"children":3551},{"href":3549,"rel":3550},"https://blog.artandlogic.com/ckeefer/2020-1/why-vue",[93],[3552],{"type":26,"value":3553},"preferred frontend Web framework",{"type":26,"value":3555},". Now, in 2024, we feel it's time to revisit the frontend framework landscape to see how things have (or haven't) changed.",{"type":21,"tag":22,"props":3557,"children":3558},{},[3559,3561,3568,3570,3577],{"type":26,"value":3560},"Up for consideration, aside from Vue, are two similar frameworks: the dominant ",{"type":21,"tag":29,"props":3562,"children":3565},{"href":3563,"rel":3564},"https://react.dev/",[93],[3566],{"type":26,"value":3567},"React.js",{"type":26,"value":3569},", and the minimalist up-and-comer ",{"type":21,"tag":29,"props":3571,"children":3574},{"href":3572,"rel":3573},"https://svelte.dev/",[93],[3575],{"type":26,"value":3576},"Svelte",{"type":26,"value":378},{"type":21,"tag":22,"props":3579,"children":3580},{},[3581,3583,3590,3592,3599],{"type":26,"value":3582},"React, the original declarative component framework, is now over 10 years old, and is the most popular frontend framework by quite a large margin. It describes itself modestly as \"a JavaScript library for building user interfaces\" and, like Vue, it uses a runtime ",{"type":21,"tag":29,"props":3584,"children":3587},{"href":3585,"rel":3586},"https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features#rendering_elements",[93],[3588],{"type":26,"value":3589},"Virtual DOM",{"type":26,"value":3591}," system to manage component updates. Components are defined in ",{"type":21,"tag":29,"props":3593,"children":3596},{"href":3594,"rel":3595},"https://react.dev/learn/writing-markup-with-jsx",[93],[3597],{"type":26,"value":3598},"JSX",{"type":26,"value":3600},", a syntax which mixes JavaScript and HTML.",{"type":21,"tag":22,"props":3602,"children":3603},{},[3604],{"type":26,"value":3605},"Svelte distinguishes itself by providing a similar declarative component development experience to React and Vue, but without a Virtual DOM runtime; it instead outputs code to directly modify the DOM. This is intended to create extremely lean and performant pages while still providing the same capabilities as a Virtual DOM based framework. It describes itself somewhat less modestly as \"cybernetically enhanced web apps\" (formerly \"the magical disappearing UI framework\"), and is the youngest of the three under consideration.",{"type":21,"tag":22,"props":3607,"children":3608},{},[3609],{"type":26,"value":3610},"Vue bills itself as \"the progressive JavaScript framework\", and was initially released a year after React. It too is based on a Virtual DOM runtime but, like Svelte (and unlike React), it typically uses a template system for rendering components rather than JSX. It aims to offer the same capabilities as frameworks like React, but in a smaller and incrementally-adoptable package.",{"type":21,"tag":22,"props":3612,"children":3613},{},[3614],{"type":26,"value":3615},"We'll be comparing these frameworks in terms of:",{"type":21,"tag":3617,"props":3618,"children":3619},"ul",{},[3620,3626,3631,3636,3641,3646,3651,3656],{"type":21,"tag":3621,"props":3622,"children":3623},"li",{},[3624],{"type":26,"value":3625},"Complexity for developers",{"type":21,"tag":3621,"props":3627,"children":3628},{},[3629],{"type":26,"value":3630},"Performance",{"type":21,"tag":3621,"props":3632,"children":3633},{},[3634],{"type":26,"value":3635},"Ecosystem",{"type":21,"tag":3621,"props":3637,"children":3638},{},[3639],{"type":26,"value":3640},"Features",{"type":21,"tag":3621,"props":3642,"children":3643},{},[3644],{"type":26,"value":3645},"Small-scale viability",{"type":21,"tag":3621,"props":3647,"children":3648},{},[3649],{"type":26,"value":3650},"Retrofit and migration viability",{"type":21,"tag":3621,"props":3652,"children":3653},{},[3654],{"type":26,"value":3655},"Large-scale viability",{"type":21,"tag":3621,"props":3657,"children":3658},{},[3659],{"type":26,"value":3660},"TypeScript Support",{"type":21,"tag":22,"props":3662,"children":3663},{},[3664,3666,3673,3675,3682,3684,3691],{"type":26,"value":3665},"Before we start however, a quick nomenclature distinction needs to be made between \"framework\", meaning React/Svelte/Vue, and \"meta-framework\", meaning an expansive collection of tooling built around a given framework. Examples of meta-frameworks would be ",{"type":21,"tag":29,"props":3667,"children":3670},{"href":3668,"rel":3669},"https://nextjs.org/",[93],[3671],{"type":26,"value":3672},"Next.js",{"type":26,"value":3674}," for React, ",{"type":21,"tag":29,"props":3676,"children":3679},{"href":3677,"rel":3678},"https://nuxt.com/",[93],[3680],{"type":26,"value":3681},"Nuxt",{"type":26,"value":3683}," for Vue, and ",{"type":21,"tag":29,"props":3685,"children":3688},{"href":3686,"rel":3687},"https://kit.svelte.dev/",[93],[3689],{"type":26,"value":3690},"SvelteKit",{"type":26,"value":3692}," for Svelte. Each of them provide features like code-splitting, server-side rendering, link pre-fetching, a prescribed project structure, and many other things that are typically needed in larger projects. We won't be digging into these meta-frameworks in detail, mainly because there's a lot of ground to cover there and they offer largely the same types of functionality, but we won't be ignoring them either; that's because these frameworks themselves are quite narrow in scope, so it's common in practice to need to lean on the capabilities of a meta-framework in order to build complex Web applications.",{"type":21,"tag":22,"props":3694,"children":3695},{},[3696],{"type":26,"value":3697},"With that out of the way, let's start by looking at ease of use for developers.",{"type":21,"tag":3699,"props":3700,"children":3702},"h2",{"id":3701},"complexity-for-developers",[3703],{"type":26,"value":3704},"Complexity for Developers",{"type":21,"tag":22,"props":3706,"children":3707},{},[3708],{"type":26,"value":3709},"Ultimately, frontend frameworks have a pretty narrow scope: they help developers to organize their components, and then put HTML and CSS on the page. Consequently, it's a shame if valuable developer brainpower gets diverted to managing the complexity of a frontend framework, at the expense of delivering more value or of minimizing technical debt.",{"type":21,"tag":22,"props":3711,"children":3712},{},[3713],{"type":26,"value":3714},"Svelte, by design, is the standout winner in terms of remaining simple; it provides templated components and basic state management, defers anything fancier than that to a meta-framework like SvelteKit, and otherwise largely stays out of the developer's way. The documentation is concise, focused, and easy for a new developer to take in. That said, I find this simplicity to be a double-edged sword: by having such a narrow focus, it means that for nontrivial projects you'll almost certainly be using it in conjunction with SvelteKit or complementary libraries, at which point it's... not all that much simpler than the competition.",{"type":21,"tag":22,"props":3716,"children":3717},{},[3718],{"type":26,"value":3719},"Vue is a step up in complexity compared to Svelte, adding multiple styles for writing components (Options API vs Composition API, templates vs JSX) and a number of bells and whistles that are only possible in a framework that uses a runtime and a Virtual DOM rendering system. The multitude of ways of doing things is arguably more of a historical problem than it is a lasting complexity, since the Composition API is the clear choice going forward. What's nice about Vue is that its features are progressive: you can learn the very basics and be able to write good, idiomatic Vue code, and then introduce larger concepts as you go along.",{"type":21,"tag":22,"props":3721,"children":3722},{},[3723,3725,3732,3734,3741,3742,3749],{"type":26,"value":3724},"React suffers, I think, from being the first Virtual DOM component library on the scene. Its original reactivity model, for example, caused components to completely re-render much more often than necessary, and so the framework introduced ",{"type":21,"tag":29,"props":3726,"children":3729},{"href":3727,"rel":3728},"https://legacy.reactjs.org/docs/hooks-intro.html",[93],[3730],{"type":26,"value":3731},"Hooks",{"type":26,"value":3733}," in order to offer better control and, consequently, better performance. Hooks are difficult to get right, however (",{"type":21,"tag":29,"props":3735,"children":3738},{"href":3736,"rel":3737},"https://adevnadia.medium.com/how-to-usememo-and-usecallback-you-can-remove-most-of-them-b8ef01b2020d",[93],[3739],{"type":26,"value":3740},"Example 1",{"type":26,"value":408},{"type":21,"tag":29,"props":3743,"children":3746},{"href":3744,"rel":3745},"https://adevnadia.medium.com/react-re-renders-guide-preventing-unnecessary-re-renders-8a3d2acbdba3",[93],[3747],{"type":26,"value":3748},"Example 2",{"type":26,"value":3750},"), and Vue and Svelte offer the same or better reactive state management without the same level of manual management. It's a similar story across much of React's APIs: through being by far the most popular framework, it has grown to have a very wide range of capabilities, but this also greatly increases the scope of what developers need to learn in order to be productive React developers.",{"type":21,"tag":3699,"props":3752,"children":3754},{"id":3753},"performance",[3755],{"type":26,"value":3630},{"type":21,"tag":22,"props":3757,"children":3758},{},[3759],{"type":26,"value":3760},"Performance is critical for Web apps, and frameworks achieve good performance in a number of ways, but primarily by minimizing the size of bundled scripts and by reducing the overhead of rendering components on the page.",{"type":21,"tag":22,"props":3762,"children":3763},{},[3764],{"type":26,"value":3765},"Comparing the performance of these frameworks is nuanced, because of the way Svelte's design differs from React's and Vue's. The other two each include a runtime in the page which, among other things, updates the document using Virtual DOM diffing: the runtime compares the DOM to the Virtual DOM to identify which changes have been made, and then surgically applies those changes to the DOM. Svelte on the other hand, for each place where a component could make changes to the DOM, introduces a snippet of script which applies precisely that one change, much like you might do by hand if you weren't using a component framework. This avoids the potentially-costly step of diffing the DOM in order to identify changes.",{"type":21,"tag":22,"props":3767,"children":3768},{},[3769,3771,3776,3778,3785,3786,3793],{"type":26,"value":3770},"As far as bundle size goes, this means that there is a break-even point between Svelte and React/Vue. A Svelte project will initially have a near-zero bundle size because there is no framework runtime to include, but on a per-component basis, it adds ",{"type":21,"tag":1084,"props":3772,"children":3773},{},[3774],{"type":26,"value":3775},"more",{"type":26,"value":3777}," script than a Virtual DOM based framework, so for larger projects, Svelte's bundle size advantages will diminish or even reverse (",{"type":21,"tag":29,"props":3779,"children":3782},{"href":3780,"rel":3781},"https://github.com/halfnelson/svelte-it-will-scale",[93],[3783],{"type":26,"value":3784},"Analysis 1",{"type":26,"value":408},{"type":21,"tag":29,"props":3787,"children":3790},{"href":3788,"rel":3789},"https://github.com/yyx990803/vue-svelte-size-analysis",[93],[3791],{"type":26,"value":3792},"Analysis 2",{"type":26,"value":2699},{"type":21,"tag":22,"props":3795,"children":3796},{},[3797,3799,3806],{"type":26,"value":3798},"Even if a large Svelte project ships more bytes of script, however, it avoids the overhead of Virtual DOM diffing, which is an advantage, and there are several tricks that can be utilized in order to compensate for having to download more script (like code-splitting or ",{"type":21,"tag":29,"props":3800,"children":3803},{"href":3801,"rel":3802},"https://kit.svelte.dev/docs/link-options#data-sveltekit-preload-data",[93],[3804],{"type":26,"value":3805},"link preloading",{"type":26,"value":3807},"). So overall, it's very hard to say with certainty whether a given project would see a meaningful performance difference between these three frameworks.",{"type":21,"tag":22,"props":3809,"children":3810},{},[3811],{"type":26,"value":3812},"There are a couple of ways to get a rough idea, however, the first being to look at benchmarks:",{"type":21,"tag":22,"props":3814,"children":3815},{},[3816],{"type":21,"tag":3817,"props":3818,"children":3821},"img",{"alt":3819,"src":3820},"React, Svelte and Vue benchmarks. Source: https://krausest.github.io/js-framework-benchmark/current.html","/phendry/2023-11-06/img/Benchmarks.png",[],{"type":21,"tag":22,"props":3823,"children":3824},{},[3825],{"type":26,"value":3826},"Despite Svelte's claimed performance benefits, it doesn't perform meaningfully better than Vue, whereas React lags a little behind.",{"type":21,"tag":22,"props":3828,"children":3829},{},[3830,3832,3839],{"type":26,"value":3831},"A more realistic comparison is the aptly-named ",{"type":21,"tag":29,"props":3833,"children":3836},{"href":3834,"rel":3835},"https://medium.com/dailyjs/a-realworld-comparison-of-front-end-frameworks-2020-4e50655fe4c1",[93],[3837],{"type":26,"value":3838},"Real World demo application",{"type":26,"value":3840},", in which Svelte performs great, Vue performs almost as well, and React again lags a little behind.",{"type":21,"tag":22,"props":3842,"children":3843},{},[3844,3846,3851,3853,3858],{"type":26,"value":3845},"The big thing to remember with these comparisons however is that these are ",{"type":21,"tag":1084,"props":3847,"children":3848},{},[3849],{"type":26,"value":3850},"meticulously-crafted",{"type":26,"value":3852}," submissions meant to get the best possible score; real-world performance will depend much more on how ",{"type":21,"tag":1084,"props":3854,"children":3855},{},[3856],{"type":26,"value":3857},"easy",{"type":26,"value":3859}," the framework makes it for time-starved developers to write performant code (see the \"Complexity for Developers\" section above). With its manually-managed hooks, React makes this considerably harder than the others, and consequently it has a reputation for making it easy for developers to inadvertently create performance problems.",{"type":21,"tag":22,"props":3861,"children":3862},{},[3863],{"type":26,"value":3864},"Overall, for mid- to large-sized Web apps, I don't think there is a strong performance reason to favour one framework over the others. Svelte may be little faster and React a little slower, but all three frameworks can be extremely fast and responsive.",{"type":21,"tag":3699,"props":3866,"children":3868},{"id":3867},"ecosystem",[3869],{"type":26,"value":3635},{"type":21,"tag":22,"props":3871,"children":3872},{},[3873],{"type":26,"value":3874},"No nontrivial modern Web application is created without leveraging many additional libraries to manage tasks like client-side routing, state management, authentication, or UI components, and many of these libraries integrate closely with the framework. Consequently it's a liability to use a framework which has a small ecosystem of third-party libraries to lean on, and a boon to use a framework with a rich ecosystem any many well-supported options.",{"type":21,"tag":22,"props":3876,"children":3877},{},[3878],{"type":26,"value":3879},"There's also the issue of talent, in that it is much easier to find developers with experience with a popular tool than a less popular one. The importance of this depends on how easy it is for an experienced developer to learn (see \"Complexity for Developers\" above).",{"type":21,"tag":22,"props":3881,"children":3882},{},[3883,3885,3892],{"type":26,"value":3884},"React has by far the biggest ecosystem of any frontend framework. In a recent ",{"type":21,"tag":29,"props":3886,"children":3889},{"href":3887,"rel":3888},"https://survey.stackoverflow.co/2023/#most-popular-technologies-webframe-prof",[93],[3890],{"type":26,"value":3891},"Stack Overflow Developer Survey",{"type":26,"value":3893},", it dwarfs Vue and Svelte in usage among professional developers:",{"type":21,"tag":22,"props":3895,"children":3896},{},[3897],{"type":21,"tag":3817,"props":3898,"children":3901},{"alt":3899,"src":3900},"Reported usage of Web frameworks among professional developers. Source: Stack Overflow","/phendry/2023-11-06/img/Popularity.png",[],{"type":21,"tag":22,"props":3903,"children":3904},{},[3905],{"type":26,"value":3906},"For a tech lead looking to make a practical choice of framework, this really makes React the default choice if all else is equal, in my mind. If any of these frameworks could meet your project's needs, then why wouldn't you select the one that makes it easiest to fill out a team of experienced developers, and the easiest to find whatever third-party libraries your team needs in order to be productive? The further you stray from the well-travelled path, the more challenging it becomes, and so the advantages of a less-popular choice need to be quite substantial.",{"type":21,"tag":22,"props":3908,"children":3909},{},[3910],{"type":26,"value":3911},"To their credit, though, none of these frameworks have an ecosystem that feels lacking, even Svelte. Each has one or more popular meta-frameworks (Next.js for React, Nuxt for Vue, SvelteKit for Svelte) which provide the advanced and server-integrated features that modern Web apps increasingly demand, and a wide range of well-supported libraries.",{"type":21,"tag":3699,"props":3913,"children":3915},{"id":3914},"features",[3916],{"type":26,"value":3640},{"type":21,"tag":22,"props":3918,"children":3919},{},[3920],{"type":26,"value":3921},"While each framework's corresponding meta-frameworks compete on all sorts of advanced features, honestly... for typical projects, there are few meaningful differences between the capabilities of these frameworks. Without going into great detail about every feature they offer and how they compare, the bottom line is that React, Svelte and Vue are all capable of building feature-rich and complex Web applications, and they all offer great TypeScript support, editor plugins, and tooling.",{"type":21,"tag":22,"props":3923,"children":3924},{},[3925,3927,3932],{"type":26,"value":3926},"There are two notable exceptions worth mentioning. The first, and it's a small one, is that Svelte lacks \"render function\" capabilities, i.e. the ability to skip the template system and write a custom function whose output is the HTML content of a component. This limitation is fundamental to Svelte's runtime-less design. Having personally a great deal of experience working within template systems, I would say that in practice this is typically only a limitation for plug-in libraries seeking to be especially generic and flexible; I can't recall ever ",{"type":21,"tag":1084,"props":3928,"children":3929},{},[3930],{"type":26,"value":3931},"needing",{"type":26,"value":3933}," a render function in order to meet a project goal. The limitation is present however, and likely affects the capabilities of third-party packages.",{"type":21,"tag":22,"props":3935,"children":3936},{},[3937,3939,3946,3948,3954,3956,3963],{"type":26,"value":3938},"The second and more important difference is that React has native Android/iOS capabilities via ",{"type":21,"tag":29,"props":3940,"children":3943},{"href":3941,"rel":3942},"https://reactnative.dev/",[93],[3944],{"type":26,"value":3945},"React Native",{"type":26,"value":3947}," that are unmatched by NativeScript-based tools for ",{"type":21,"tag":29,"props":3949,"children":3952},{"href":3950,"rel":3951},"https://svelte-native.technology",[93],[3953],{"type":26,"value":3576},{"type":26,"value":3955}," and for ",{"type":21,"tag":29,"props":3957,"children":3960},{"href":3958,"rel":3959},"https://nativescript-vue.org/",[93],[3961],{"type":26,"value":3962},"Vue",{"type":26,"value":3964},", in terms of production-readiness. If it's valuable for your project to be able to build a native mobile app using a Web developer skillset rather than native Android or iOS development skills, then React is the framework which can deliver that.",{"type":21,"tag":3699,"props":3966,"children":3968},{"id":3967},"small-scale-viability",[3969],{"type":26,"value":3970},"Small-scale Viability",{"type":21,"tag":22,"props":3972,"children":3973},{},[3974],{"type":26,"value":3975},"At Art+Logic we work on projects ranging from very small to reasonably large, so there is a lot of value in working with a frontend framework that is suitable for the full gamut of project sizes. This should arguably be a consideration for most teams, because most small projects could find themselves needing to scale up, and most large projects end up having small complementary projects like internal tools.",{"type":21,"tag":22,"props":3977,"children":3978},{},[3979,3981,3996],{"type":26,"value":3980},"One of Vue's capabilities that makes it uniquely suited for small projects is that ",{"type":21,"tag":29,"props":3982,"children":3985},{"href":3983,"rel":3984},"https://vuejs.org/guide/quick-start.html#using-vue-from-cdn",[93],[3986,3988,3994],{"type":26,"value":3987},"it can be used via a CDN ",{"type":21,"tag":63,"props":3989,"children":3991},{"className":3990},[],[3992],{"type":26,"value":3993},"\u003Cscript>",{"type":26,"value":3995}," tag without any build system whatsoever",{"type":26,"value":3997},". This means you can inject Vue onto a static page to introduce dynamic functionality to just a portion of it, or easily inject Vue into a project built using a different framework altogether. React and Svelte on the other hand are decidedly geared towards building a project within the bounds of their tooling ecosystems, limiting their small-scale flexibility.",{"type":21,"tag":22,"props":3999,"children":4000},{},[4001],{"type":26,"value":4002},"For a green-field project however, Svelte's wafer-thin bundle sizes make it a great choice for small-scale or low-complexity projects. React, having the heftiest runtime of the bunch, is perhaps less advisable for a small project, but still is perfectly serviceable.",{"type":21,"tag":3699,"props":4004,"children":4006},{"id":4005},"retrofit-and-migration-viability",[4007],{"type":26,"value":4008},"Retrofit and Migration Viability",{"type":21,"tag":22,"props":4010,"children":4011},{},[4012],{"type":26,"value":4013},"With the frustratingly-fast pace of evolution in frontend Web development tooling over the last couple decades, many teams are left with older projects whose choice of framework has become a hindrance to continued development. A full re-write is a risky proposition, so it's powerful to have the ability to implement a gradual extension or migration in a modern framework.",{"type":21,"tag":22,"props":4015,"children":4016},{},[4017],{"type":26,"value":4018},"Vue again is uniquely positioned in this regard: being the self-described \"progressive framework\", it is much more practical than the others to integrate into an existing project built with another framework. In React or Svelte, I would likely not attempt to anything more granular than a page-by-page conversion, but with Vue, it's easy to embed Vue within an existing codebase and build system. I once had occasion to implement a Backbone.js component which renders a Vue component, which in turns renders a Backbone.js component; you'll have to trust me that there was a good reason for doing so!",{"type":21,"tag":3699,"props":4020,"children":4022},{"id":4021},"large-scale-viability",[4023],{"type":26,"value":4024},"Large-scale Viability",{"type":21,"tag":22,"props":4026,"children":4027},{},[4028],{"type":26,"value":4029},"All three of these frameworks have powerful build systems and meta-frameworks which enable all sorts of advanced performance-related features (such as prefetching links, server-side rendering, code-splitting, etc). As such, they're all able to scale up and competently handle large, complex projects.",{"type":21,"tag":22,"props":4031,"children":4032},{},[4033],{"type":26,"value":4034},"I would personally have some hesitation with using Svelte on a large project however, this being for ecosystem reasons rather than technical ones. A large project is more likely to be difficult to migrate toward alternative technologies in the future, and more likely to require a wide variety of third-party libraries, both of which arguably make conservative technology choices more appropriate. In this case, that would mean choosing a framework with a larger talent pool and third-party ecosystem (i.e. React, or to a lesser extent Vue).",{"type":21,"tag":3699,"props":4036,"children":4038},{"id":4037},"typescript-support",[4039],{"type":26,"value":3660},{"type":21,"tag":22,"props":4041,"children":4042},{},[4043],{"type":26,"value":4044},"There's not much to be said here since all three frameworks have great TypeScript support, but it's worth highlighting that fact, since TypeScript is an excellent language choice for developing a robust codebase. It would be difficult to recommend a framework in 2024 which does not provide TypeScript as a first-class option.",{"type":21,"tag":3699,"props":4046,"children":4048},{"id":4047},"summary-and-conclusion",[4049],{"type":26,"value":4050},"Summary and Conclusion",{"type":21,"tag":22,"props":4052,"children":4053},{},[4054],{"type":26,"value":4055},"To grossly oversimply the above considerations into a comparison chart:",{"type":21,"tag":4057,"props":4058,"children":4059},"table",{},[4060,4086],{"type":21,"tag":4061,"props":4062,"children":4063},"thead",{},[4064],{"type":21,"tag":4065,"props":4066,"children":4067},"tr",{},[4068,4072,4078,4082],{"type":21,"tag":4069,"props":4070,"children":4071},"th",{},[],{"type":21,"tag":4069,"props":4073,"children":4075},{"align":4074},"center",[4076],{"type":26,"value":4077},"React",{"type":21,"tag":4069,"props":4079,"children":4080},{"align":4074},[4081],{"type":26,"value":3576},{"type":21,"tag":4069,"props":4083,"children":4084},{"align":4074},[4085],{"type":26,"value":3962},{"type":21,"tag":4087,"props":4088,"children":4089},"tbody",{},[4090,4113,4132,4151,4170,4189,4208,4227],{"type":21,"tag":4065,"props":4091,"children":4092},{},[4093,4098,4103,4108],{"type":21,"tag":4094,"props":4095,"children":4096},"td",{},[4097],{"type":26,"value":3625},{"type":21,"tag":4094,"props":4099,"children":4100},{"align":4074},[4101],{"type":26,"value":4102},"🔴",{"type":21,"tag":4094,"props":4104,"children":4105},{"align":4074},[4106],{"type":26,"value":4107},"🟢",{"type":21,"tag":4094,"props":4109,"children":4110},{"align":4074},[4111],{"type":26,"value":4112},"🟡",{"type":21,"tag":4065,"props":4114,"children":4115},{},[4116,4120,4124,4128],{"type":21,"tag":4094,"props":4117,"children":4118},{},[4119],{"type":26,"value":3630},{"type":21,"tag":4094,"props":4121,"children":4122},{"align":4074},[4123],{"type":26,"value":4112},{"type":21,"tag":4094,"props":4125,"children":4126},{"align":4074},[4127],{"type":26,"value":4107},{"type":21,"tag":4094,"props":4129,"children":4130},{"align":4074},[4131],{"type":26,"value":4107},{"type":21,"tag":4065,"props":4133,"children":4134},{},[4135,4139,4143,4147],{"type":21,"tag":4094,"props":4136,"children":4137},{},[4138],{"type":26,"value":3635},{"type":21,"tag":4094,"props":4140,"children":4141},{"align":4074},[4142],{"type":26,"value":4107},{"type":21,"tag":4094,"props":4144,"children":4145},{"align":4074},[4146],{"type":26,"value":4102},{"type":21,"tag":4094,"props":4148,"children":4149},{"align":4074},[4150],{"type":26,"value":4112},{"type":21,"tag":4065,"props":4152,"children":4153},{},[4154,4158,4162,4166],{"type":21,"tag":4094,"props":4155,"children":4156},{},[4157],{"type":26,"value":3640},{"type":21,"tag":4094,"props":4159,"children":4160},{"align":4074},[4161],{"type":26,"value":4107},{"type":21,"tag":4094,"props":4163,"children":4164},{"align":4074},[4165],{"type":26,"value":4107},{"type":21,"tag":4094,"props":4167,"children":4168},{"align":4074},[4169],{"type":26,"value":4107},{"type":21,"tag":4065,"props":4171,"children":4172},{},[4173,4177,4181,4185],{"type":21,"tag":4094,"props":4174,"children":4175},{},[4176],{"type":26,"value":3645},{"type":21,"tag":4094,"props":4178,"children":4179},{"align":4074},[4180],{"type":26,"value":4112},{"type":21,"tag":4094,"props":4182,"children":4183},{"align":4074},[4184],{"type":26,"value":4107},{"type":21,"tag":4094,"props":4186,"children":4187},{"align":4074},[4188],{"type":26,"value":4107},{"type":21,"tag":4065,"props":4190,"children":4191},{},[4192,4196,4200,4204],{"type":21,"tag":4094,"props":4193,"children":4194},{},[4195],{"type":26,"value":3650},{"type":21,"tag":4094,"props":4197,"children":4198},{"align":4074},[4199],{"type":26,"value":4112},{"type":21,"tag":4094,"props":4201,"children":4202},{"align":4074},[4203],{"type":26,"value":4112},{"type":21,"tag":4094,"props":4205,"children":4206},{"align":4074},[4207],{"type":26,"value":4107},{"type":21,"tag":4065,"props":4209,"children":4210},{},[4211,4215,4219,4223],{"type":21,"tag":4094,"props":4212,"children":4213},{},[4214],{"type":26,"value":3655},{"type":21,"tag":4094,"props":4216,"children":4217},{"align":4074},[4218],{"type":26,"value":4107},{"type":21,"tag":4094,"props":4220,"children":4221},{"align":4074},[4222],{"type":26,"value":4112},{"type":21,"tag":4094,"props":4224,"children":4225},{"align":4074},[4226],{"type":26,"value":4107},{"type":21,"tag":4065,"props":4228,"children":4229},{},[4230,4234,4238,4242],{"type":21,"tag":4094,"props":4231,"children":4232},{},[4233],{"type":26,"value":3660},{"type":21,"tag":4094,"props":4235,"children":4236},{"align":4074},[4237],{"type":26,"value":4107},{"type":21,"tag":4094,"props":4239,"children":4240},{"align":4074},[4241],{"type":26,"value":4107},{"type":21,"tag":4094,"props":4243,"children":4244},{"align":4074},[4245],{"type":26,"value":4107},{"type":21,"tag":22,"props":4247,"children":4248},{},[4249],{"type":26,"value":4250},"In general, React, Svelte and Vue are all excellent and production-ready frameworks, and a strong case can be made for any one of them. React offers a drastically larger ecosystem and talent pool in addition to native mobile capabilities, though it suffers from a higher complexity for developers and somewhat less reliable performance. Svelte offers cutting-edge performance, but its ecosystem is less mature. Vue sits somewhere in the middle, and offers the greatest versatility for a wide variety of project scenarios.",{"type":21,"tag":22,"props":4252,"children":4253},{},[4254],{"type":26,"value":4255},"At Art+Logic, where \"coding the 'impossible'\" can take any number of forms, versatility continues to be one of the most valuable things we look for in a framework, and Vue continues to provide the most versatility while still ticking all the other boxes we expect it to. As such, it continues to be our preferred choice for frontend Web development.",{"title":8,"searchDepth":254,"depth":254,"links":4257},[4258,4259,4260,4261,4262,4263,4264,4265,4266],{"id":3701,"depth":244,"text":3704},{"id":3753,"depth":244,"text":3630},{"id":3867,"depth":244,"text":3635},{"id":3914,"depth":244,"text":3640},{"id":3967,"depth":244,"text":3970},{"id":4005,"depth":244,"text":4008},{"id":4021,"depth":244,"text":4024},{"id":4037,"depth":244,"text":3660},{"id":4047,"depth":244,"text":4050},"content:phendry:2023-11-06:FrontendFrameworksIn2024.md","phendry/2023-11-06/FrontendFrameworksIn2024.md","phendry/2023-11-06/FrontendFrameworksIn2024",{"user":4271,"name":4272},"phendry","Paul Hendry",{"_path":4274,"_dir":4275,"_draft":7,"_partial":7,"_locale":8,"title":4276,"description":4277,"tags":4278,"publishDate":4280,"image":4281,"excerpt":4277,"body":4282,"_type":3511,"_id":5046,"_source":3513,"_file":5047,"_stem":5048,"_extension":3516,"author":5049},"/phendry/2021-06/smoothupgradestovue3","2021-06","Smooth Upgrades to Vue 3","This post assumes basic familiarity with Vue.js v2.x.",[12,13,4279],"how-to","2021-07-01","/phendry/2021-06/img/vue-transition.jpg",{"type":18,"children":4283,"toc":5040},[4284,4299,4304,4441,4455,4469,4475,4487,4559,4571,4577,4582,4634,4639,4645,4659,4664,4755,4769,4832,4845,4913,4919,4924,5014,5036],{"type":21,"tag":22,"props":4285,"children":4286},{},[4287],{"type":21,"tag":1084,"props":4288,"children":4289},{},[4290,4292,4298],{"type":26,"value":4291},"This post assumes basic familiarity with ",{"type":21,"tag":29,"props":4293,"children":4295},{"href":3540,"rel":4294},[93],[4296],{"type":26,"value":4297},"Vue.js v2.x",{"type":26,"value":378},{"type":21,"tag":22,"props":4300,"children":4301},{},[4302],{"type":26,"value":4303},"Vue 3, the Progressive JavaScript Framework, introduces some compelling new features:",{"type":21,"tag":3617,"props":4305,"children":4306},{},[4307,4319,4342,4364,4376,4388,4406,4428],{"type":21,"tag":3621,"props":4308,"children":4309},{},[4310,4311,4317],{"type":26,"value":108},{"type":21,"tag":29,"props":4312,"children":4315},{"href":4313,"rel":4314},"https://v3.vuejs.org/guide/composition-api-introduction.html",[93],[4316],{"type":26,"value":189},{"type":26,"value":4318}," introduces a new, more flexible, TypeScript-friendly syntax for defining components (albeit at the cost of a bit more complexity);",{"type":21,"tag":3621,"props":4320,"children":4321},{},[4322,4324,4331,4333,4340],{"type":26,"value":4323},"Significant ",{"type":21,"tag":29,"props":4325,"children":4328},{"href":4326,"rel":4327},"https://docs.google.com/spreadsheets/d/1VJFx-kQ4KjJmnpDXIEaig-cVAAJtpIGLZNbv3Lr4CR0/edit#gid=0",[93],[4329],{"type":26,"value":4330},"reported performance improvements",{"type":26,"value":4332}," over v2, in addition to reduced bundle sizes as a result of ",{"type":21,"tag":29,"props":4334,"children":4337},{"href":4335,"rel":4336},"https://v3.vuejs.org/guide/migration/global-api-treeshaking.html",[93],[4338],{"type":26,"value":4339},"global API tree-shaking",{"type":26,"value":4341},";",{"type":21,"tag":3621,"props":4343,"children":4344},{},[4345,4347,4354,4356,4362],{"type":26,"value":4346},"An updated ",{"type":21,"tag":29,"props":4348,"children":4351},{"href":4349,"rel":4350},"https://v3.vuejs.org/guide/reactivity.html#what-is-reactivity",[93],[4352],{"type":26,"value":4353},"reactivity system",{"type":26,"value":4355}," based on ",{"type":21,"tag":63,"props":4357,"children":4359},{"className":4358},[],[4360],{"type":26,"value":4361},"Proxy",{"type":26,"value":4363},", which eliminates a common source of bugs when using arrays and objects;",{"type":21,"tag":3621,"props":4365,"children":4366},{},[4367,4374],{"type":21,"tag":29,"props":4368,"children":4371},{"href":4369,"rel":4370},"https://vitejs.dev/",[93],[4372],{"type":26,"value":4373},"Vite",{"type":26,"value":4375},", a new set of frontend tooling for a lightning-fast development experience;",{"type":21,"tag":3621,"props":4377,"children":4378},{},[4379,4386],{"type":21,"tag":29,"props":4380,"children":4383},{"href":4381,"rel":4382},"https://v3.vuejs.org/guide/migration/fragments.html",[93],[4384],{"type":26,"value":4385},"Fragments",{"type":26,"value":4387},", allowing multiple root elements in Vue components;",{"type":21,"tag":3621,"props":4389,"children":4390},{},[4391,4393,4404],{"type":26,"value":4392},"[Experimental] The ",{"type":21,"tag":29,"props":4394,"children":4397},{"href":4395,"rel":4396},"https://github.com/vuejs/rfcs/blob/script-setup-2/active-rfcs/0000-script-setup.md",[93],[4398],{"type":21,"tag":63,"props":4399,"children":4401},{"className":4400},[],[4402],{"type":26,"value":4403},"\u003Cscript setup>",{"type":26,"value":4405}," syntax, for a nicer syntax when committing fully to the Composition API in a component;",{"type":21,"tag":3621,"props":4407,"children":4408},{},[4409,4411,4418,4420,4426],{"type":26,"value":4410},"[Experimental] ",{"type":21,"tag":29,"props":4412,"children":4415},{"href":4413,"rel":4414},"https://github.com/vuejs/rfcs/blob/style-vars-2/active-rfcs/0000-sfc-style-variables.md",[93],[4416],{"type":26,"value":4417},"State-driven CSS Variables",{"type":26,"value":4419},", allowing data bindings within the ",{"type":21,"tag":63,"props":4421,"children":4423},{"className":4422},[],[4424],{"type":26,"value":4425},"\u003Cstyle>",{"type":26,"value":4427}," section of components;",{"type":21,"tag":3621,"props":4429,"children":4430},{},[4431,4432,4439],{"type":26,"value":4392},{"type":21,"tag":29,"props":4433,"children":4436},{"href":4434,"rel":4435},"https://v3.vuejs.org/guide/migration/suspense.html",[93],[4437],{"type":26,"value":4438},"Suspense",{"type":26,"value":4440}," component, which makes it much easier to write asynchronous components that display a \"loading\" UI while they're processing.",{"type":21,"tag":22,"props":4442,"children":4443},{},[4444,4446,4453],{"type":26,"value":4445},"It's a valuable upgrade in terms of performance and developer productivity. The question is, how do you get there? While v3 does not make any drastic API changes compared to v2, the changes it does make are ",{"type":21,"tag":29,"props":4447,"children":4450},{"href":4448,"rel":4449},"https://v3.vuejs.org/guide/migration/introduction.html#breaking-changes",[93],[4451],{"type":26,"value":4452},"numerous",{"type":26,"value":4454},", and as of the initial v3.0 release, these breaking changes would need to be migrated in one fell swoop.",{"type":21,"tag":22,"props":4456,"children":4457},{},[4458,4460,4467],{"type":26,"value":4459},"Fortunately, the Vue.js team has recently released the ",{"type":21,"tag":29,"props":4461,"children":4464},{"href":4462,"rel":4463},"https://v3.vuejs.org/guide/migration/migration-build.html",[93],[4465],{"type":26,"value":4466},"Migration Build",{"type":26,"value":4468},", which makes it possible (and easy) to make a smooth transition from v2 to v3.",{"type":21,"tag":3699,"props":4470,"children":4472},{"id":4471},"vue-3-compatibility-caveats",[4473],{"type":26,"value":4474},"Vue 3 Compatibility Caveats",{"type":21,"tag":22,"props":4476,"children":4477},{},[4478,4480,4485],{"type":26,"value":4479},"There are a few reasons why you might ",{"type":21,"tag":1084,"props":4481,"children":4482},{},[4483],{"type":26,"value":4484},"not",{"type":26,"value":4486}," be ready to introduce Vue 3 into your project:",{"type":21,"tag":3617,"props":4488,"children":4489},{},[4490,4510],{"type":21,"tag":3621,"props":4491,"children":4492},{},[4493,4499,4501,4508],{"type":21,"tag":4494,"props":4495,"children":4496},"strong",{},[4497],{"type":26,"value":4498},"IE11 Compatibility:",{"type":26,"value":4500}," Support for Internet Exporer 11 and other \"legacy\" browsers was previously promised in a subsequent update, but it has been ",{"type":21,"tag":29,"props":4502,"children":4505},{"href":4503,"rel":4504},"https://github.com/vuejs/rfcs/blob/master/active-rfcs/0038-vue3-ie11-support.md",[93],[4506],{"type":26,"value":4507},"formally dropped",{"type":26,"value":4509}," from the Vue 3 roadmap. If your project needs to support IE or other \"legacy\" browsers, you'll likely be sticking to Vue v2.x indefinitely.",{"type":21,"tag":3621,"props":4511,"children":4512},{},[4513,4518,4520],{"type":21,"tag":4494,"props":4514,"children":4515},{},[4516],{"type":26,"value":4517},"Framework Compatibiilty:",{"type":26,"value":4519}," Many major component libraries and frameworks need time to make the upgrade. If you depend on one of them, you'll be dependent on their upgrade to v3. For example:\n",{"type":21,"tag":3617,"props":4521,"children":4522},{},[4523,4535,4547],{"type":21,"tag":3621,"props":4524,"children":4525},{},[4526,4528],{"type":26,"value":4527},"Bootstrap-Vue: ",{"type":21,"tag":29,"props":4529,"children":4532},{"href":4530,"rel":4531},"https://github.com/bootstrap-vue/bootstrap-vue/issues/5196",[93],[4533],{"type":26,"value":4534},"On roadmap, but no timeline",{"type":21,"tag":3621,"props":4536,"children":4537},{},[4538,4540],{"type":26,"value":4539},"Nuxt.js: ",{"type":21,"tag":29,"props":4541,"children":4544},{"href":4542,"rel":4543},"https://github.com/nuxt/nuxt.js/issues/5708",[93],[4545],{"type":26,"value":4546},"On roadmap for Nuxt v3, but no timeline",{"type":21,"tag":3621,"props":4548,"children":4549},{},[4550,4552],{"type":26,"value":4551},"Vuetify: ",{"type":21,"tag":29,"props":4553,"children":4556},{"href":4554,"rel":4555},"https://vuetifyjs.com/en/introduction/roadmap/",[93],[4557],{"type":26,"value":4558},"support available in Vuetify v3.0 alpha; full support in Q3 2021",{"type":21,"tag":22,"props":4560,"children":4561},{},[4562,4564,4570],{"type":26,"value":4563},"Make sure that your project's dependencies and supported platforms allow for the upgrade. If not, keep in mind that some v3 features are being backported to v2, such as the ",{"type":21,"tag":29,"props":4565,"children":4568},{"href":4566,"rel":4567},"https://github.com/vuejs/composition-api",[93],[4569],{"type":26,"value":189},{"type":26,"value":378},{"type":21,"tag":3699,"props":4572,"children":4574},{"id":4573},"what-is-the-migration-build",[4575],{"type":26,"value":4576},"What is the Migration Build?",{"type":21,"tag":22,"props":4578,"children":4579},{},[4580],{"type":26,"value":4581},"The Migration Build is an alternative build of Vue 3 which provides configurable Vue 2 compatible behaviour. It enables a gradual migration process:",{"type":21,"tag":4583,"props":4584,"children":4585},"ol",{},[4586,4605,4610,4615],{"type":21,"tag":3621,"props":4587,"children":4588},{},[4589,4591,4596,4598,4604],{"type":26,"value":4590},"Swap out your ",{"type":21,"tag":63,"props":4592,"children":4594},{"className":4593},[],[4595],{"type":26,"value":13},{"type":26,"value":4597}," v2.x dependency with ",{"type":21,"tag":63,"props":4599,"children":4601},{"className":4600},[],[4602],{"type":26,"value":4603},"@vue/compat",{"type":26,"value":4341},{"type":21,"tag":3621,"props":4606,"children":4607},{},[4608],{"type":26,"value":4609},"Configure the Migration Build to be fully v2-compatible;",{"type":21,"tag":3621,"props":4611,"children":4612},{},[4613],{"type":26,"value":4614},"One breaking change at a time, configure the Migration Build to be v3-compatible for that feature, and fix any occurrences of it in your project;",{"type":21,"tag":3621,"props":4616,"children":4617},{},[4618,4620,4625,4627,4632],{"type":26,"value":4619},"Swap out ",{"type":21,"tag":63,"props":4621,"children":4623},{"className":4622},[],[4624],{"type":26,"value":4603},{"type":26,"value":4626}," for ",{"type":21,"tag":63,"props":4628,"children":4630},{"className":4629},[],[4631],{"type":26,"value":13},{"type":26,"value":4633}," 3.x once your project is fully migrated to v3.",{"type":21,"tag":22,"props":4635,"children":4636},{},[4637],{"type":26,"value":4638},"The amount of overhead introduced by this compability build is relatively small, so it's even possible to make releases while in the intermediate state between v2 and v3 compatibility. The Vue.js team has guaranteed to maintain this migration build at least until the end of 2021, but after that no firm commitments have been made, so if you've made the decision to upgrade, it's best not to delay for too long.",{"type":21,"tag":3699,"props":4640,"children":4642},{"id":4641},"using-the-migration-build",[4643],{"type":26,"value":4644},"Using the Migration Build",{"type":21,"tag":22,"props":4646,"children":4647},{},[4648,4650,4657],{"type":26,"value":4649},"The first step of course is installation, and the ",{"type":21,"tag":29,"props":4651,"children":4654},{"href":4652,"rel":4653},"https://v3.vuejs.org/guide/migration/migration-build.html#installation",[93],[4655],{"type":26,"value":4656},"official installation documentation",{"type":26,"value":4658}," is easy to follow.",{"type":21,"tag":22,"props":4660,"children":4661},{},[4662],{"type":26,"value":4663},"Configuration is straightforward, and can be done both globally or on a per-component basis. A global configuration can be created with a snippet like this in the root of the application:",{"type":21,"tag":200,"props":4665,"children":4667},{"className":202,"code":4666,"language":12,"meta":8,"style":8},"import { configureCompat } from 'vue';\n\nconfigureCompat({\n   // By default, each feature is v2 compatible. Set individual features to\n   // `false` like so to switch them to v3 compatibility.\n   GLOBAL_MOUNT: false,\n});\n",[4668],{"type":21,"tag":63,"props":4669,"children":4670},{"__ignoreMap":8},[4671,4695,4702,4715,4723,4731,4748],{"type":21,"tag":209,"props":4672,"children":4673},{"class":211,"line":212},[4674,4678,4683,4687,4691],{"type":21,"tag":209,"props":4675,"children":4676},{"style":216},[4677],{"type":26,"value":219},{"type":21,"tag":209,"props":4679,"children":4680},{"style":222},[4681],{"type":26,"value":4682}," { configureCompat } ",{"type":21,"tag":209,"props":4684,"children":4685},{"style":216},[4686],{"type":26,"value":230},{"type":21,"tag":209,"props":4688,"children":4689},{"style":233},[4690],{"type":26,"value":1640},{"type":21,"tag":209,"props":4692,"children":4693},{"style":222},[4694],{"type":26,"value":241},{"type":21,"tag":209,"props":4696,"children":4697},{"class":211,"line":244},[4698],{"type":21,"tag":209,"props":4699,"children":4700},{"emptyLinePlaceholder":248},[4701],{"type":26,"value":251},{"type":21,"tag":209,"props":4703,"children":4704},{"class":211,"line":254},[4705,4710],{"type":21,"tag":209,"props":4706,"children":4707},{"style":360},[4708],{"type":26,"value":4709},"configureCompat",{"type":21,"tag":209,"props":4711,"children":4712},{"style":222},[4713],{"type":26,"value":4714},"({\n",{"type":21,"tag":209,"props":4716,"children":4717},{"class":211,"line":279},[4718],{"type":21,"tag":209,"props":4719,"children":4720},{"style":448},[4721],{"type":26,"value":4722},"   // By default, each feature is v2 compatible. Set individual features to\n",{"type":21,"tag":209,"props":4724,"children":4725},{"class":211,"line":288},[4726],{"type":21,"tag":209,"props":4727,"children":4728},{"style":448},[4729],{"type":26,"value":4730},"   // `false` like so to switch them to v3 compatibility.\n",{"type":21,"tag":209,"props":4732,"children":4733},{"class":211,"line":307},[4734,4739,4744],{"type":21,"tag":209,"props":4735,"children":4736},{"style":222},[4737],{"type":26,"value":4738},"   GLOBAL_MOUNT: ",{"type":21,"tag":209,"props":4740,"children":4741},{"style":263},[4742],{"type":26,"value":4743},"false",{"type":21,"tag":209,"props":4745,"children":4746},{"style":222},[4747],{"type":26,"value":304},{"type":21,"tag":209,"props":4749,"children":4750},{"class":211,"line":325},[4751],{"type":21,"tag":209,"props":4752,"children":4753},{"style":222},[4754],{"type":26,"value":469},{"type":21,"tag":22,"props":4756,"children":4757},{},[4758,4760,4767],{"type":26,"value":4759},"Once installed and configured, your v3-upgraded application should, for the most part, function just the same as before. From here, the ",{"type":21,"tag":29,"props":4761,"children":4764},{"href":4762,"rel":4763},"https://v3.vuejs.org/guide/migration/migration-build.html#feature-reference",[93],[4765],{"type":26,"value":4766},"Feature Reference",{"type":26,"value":4768}," in the official documentation is where you'll find a list of the individual v3 features to enable in order to migrate your project. They're separated into four \"Compatibility Types\", in a sensible order for sequentially working through them. These are:",{"type":21,"tag":3617,"props":4770,"children":4771},{},[4772,4788,4798,4822],{"type":21,"tag":3621,"props":4773,"children":4774},{},[4775,4780,4782,4786],{"type":21,"tag":4494,"props":4776,"children":4777},{},[4778],{"type":26,"value":4779},"Incompatible:",{"type":26,"value":4781}," These are a handful of features for which the Migration Build does ",{"type":21,"tag":1084,"props":4783,"children":4784},{},[4785],{"type":26,"value":4484},{"type":26,"value":4787}," provide v2 compatibility; it only provides warnings for easy identification of code that requires migrating. If any of these warnings appear, they'll need to be addressed upfront.",{"type":21,"tag":3621,"props":4789,"children":4790},{},[4791,4796],{"type":21,"tag":4494,"props":4792,"children":4793},{},[4794],{"type":26,"value":4795},"Partially Compatible With Caveats:",{"type":26,"value":4797}," These features don't behave 100% identically to v2 in compatibility mode, but as long as you aren't relying on private Vue APIs, this is unlikely to be a problem.",{"type":21,"tag":3621,"props":4799,"children":4800},{},[4801,4806,4808,4812,4814,4820],{"type":21,"tag":4494,"props":4802,"children":4803},{},[4804],{"type":26,"value":4805},"Compat Only (No Warning)",{"type":26,"value":4807},": These features are v2-compatible but do ",{"type":21,"tag":1084,"props":4809,"children":4810},{},[4811],{"type":26,"value":4484},{"type":26,"value":4813}," issue a warning to identify code which needs migrating. Curently this is only the ",{"type":21,"tag":63,"props":4815,"children":4817},{"className":4816},[],[4818],{"type":26,"value":4819},"TRANSITION_CLASSES",{"type":26,"value":4821}," feature, instances of which are easy to find via text search.",{"type":21,"tag":3621,"props":4823,"children":4824},{},[4825,4830],{"type":21,"tag":4494,"props":4826,"children":4827},{},[4828],{"type":26,"value":4829},"Fully Compatible",{"type":26,"value":4831},": These features ought to behave identically to v2.",{"type":21,"tag":22,"props":4833,"children":4834},{},[4835,4837,4843],{"type":26,"value":4836},"For each feature, simply migrate each v2-style occurrence, then set ",{"type":21,"tag":63,"props":4838,"children":4840},{"className":4839},[],[4841],{"type":26,"value":4842},"FEATURE_NAME: false",{"type":26,"value":4844}," in your compatibility configuration in order to switch the Vue build to use the v3 behavior.",{"type":21,"tag":22,"props":4846,"children":4847},{},[4848,4850,4856,4858,4865,4867,4873,4875,4880,4882,4888,4890,4896,4897,4903,4905,4911],{"type":26,"value":4849},"For example, consider the ",{"type":21,"tag":63,"props":4851,"children":4853},{"className":4852},[],[4854],{"type":26,"value":4855},"INSTANCE_SCOPED_SLOTS",{"type":26,"value":4857}," compatibility feature. The Feature Reference provides a ",{"type":21,"tag":29,"props":4859,"children":4862},{"href":4860,"rel":4861},"https://v3.vuejs.org/guide/migration/slots-unification.html",[93],[4863],{"type":26,"value":4864},"link",{"type":26,"value":4866}," to the relevant migration documentation, which tells you that ",{"type":21,"tag":63,"props":4868,"children":4870},{"className":4869},[],[4871],{"type":26,"value":4872},"this.$scopedSlots",{"type":26,"value":4874}," has been removed due to the unification of normal/scoped slots in v3. The \"Migration Strategy\" section at the bottom describes simple steps to take: replace occurrences of ",{"type":21,"tag":63,"props":4876,"children":4878},{"className":4877},[],[4879],{"type":26,"value":4872},{"type":26,"value":4881}," with ",{"type":21,"tag":63,"props":4883,"children":4885},{"className":4884},[],[4886],{"type":26,"value":4887},"this.$slots",{"type":26,"value":4889},", and then replace occurrences of ",{"type":21,"tag":63,"props":4891,"children":4893},{"className":4892},[],[4894],{"type":26,"value":4895},"this.$slots.mySlot",{"type":26,"value":4881},{"type":21,"tag":63,"props":4898,"children":4900},{"className":4899},[],[4901],{"type":26,"value":4902},"this.$slots.mySlot()",{"type":26,"value":4904},". This can easily be done in a few moments using find-and-replace, after which ",{"type":21,"tag":63,"props":4906,"children":4908},{"className":4907},[],[4909],{"type":26,"value":4910},"INSTANCE_SCOPED_SLOTS: false",{"type":26,"value":4912}," can be set in your compatibility configuration, one step closer to v3 compatibility.",{"type":21,"tag":3699,"props":4914,"children":4916},{"id":4915},"recap",[4917],{"type":26,"value":4918},"Recap",{"type":21,"tag":22,"props":4920,"children":4921},{},[4922],{"type":26,"value":4923},"Overall, the Migration Build allows for a gradual development process of migration that looks something like this:",{"type":21,"tag":4583,"props":4925,"children":4926},{},[4927,4955,4960],{"type":21,"tag":3621,"props":4928,"children":4929},{},[4930,4932],{"type":26,"value":4931},"Replace your project's Vue 2.x dependency with the Vue 3 Migration Build\n",{"type":21,"tag":4583,"props":4933,"children":4934},{},[4935,4940,4945,4950],{"type":21,"tag":3621,"props":4936,"children":4937},{},[4938],{"type":26,"value":4939},"Install and configure it for full v2 compatibility",{"type":21,"tag":3621,"props":4941,"children":4942},{},[4943],{"type":26,"value":4944},"Migrate the handful of features marked \"Incompatible\" in order to restore your application to full function",{"type":21,"tag":3621,"props":4946,"children":4947},{},[4948],{"type":26,"value":4949},"Peform some smoke testing to ensure that everything is back to normal",{"type":21,"tag":3621,"props":4951,"children":4952},{},[4953],{"type":26,"value":4954},"Merge this change into your mainline development branch",{"type":21,"tag":3621,"props":4956,"children":4957},{},[4958],{"type":26,"value":4959},"Continue regular development as required, potentially even making releases along the way",{"type":21,"tag":3621,"props":4961,"children":4962},{},[4963,4965,4971,4972],{"type":26,"value":4964},"While ",{"type":21,"tag":63,"props":4966,"children":4968},{"className":4967},[],[4969],{"type":26,"value":4970},"numUnmigratedFeatures > 0",{"type":26,"value":304},{"type":21,"tag":4583,"props":4973,"children":4974},{},[4975,4987,4999,5004,5009],{"type":21,"tag":3621,"props":4976,"children":4977},{},[4978,4980,4985],{"type":26,"value":4979},"Use the ",{"type":21,"tag":29,"props":4981,"children":4983},{"href":4762,"rel":4982},[93],[4984],{"type":26,"value":4766},{"type":26,"value":4986}," documentation to identify the next compatibility feature to disable",{"type":21,"tag":3621,"props":4988,"children":4989},{},[4990,4992,4997],{"type":26,"value":4991},"Switch to v3 behavior by setting ",{"type":21,"tag":63,"props":4993,"children":4995},{"className":4994},[],[4996],{"type":26,"value":4842},{"type":26,"value":4998}," in your Migration Build configuration",{"type":21,"tag":3621,"props":5000,"children":5001},{},[5002],{"type":26,"value":5003},"Use the documentation link in the Feature Reference to jump to relevant information about how to migrate to v3",{"type":21,"tag":3621,"props":5005,"children":5006},{},[5007],{"type":26,"value":5008},"Migrate all occurrences in your project",{"type":21,"tag":3621,"props":5010,"children":5011},{},[5012],{"type":26,"value":5013},"Merge this change into your mainline development branch (which ensures that any subsequent commits must use the v3 behavior)",{"type":21,"tag":22,"props":5015,"children":5016},{},[5017,5019,5026,5028,5035],{"type":26,"value":5018},"This easy and comprehensive upgrade process, combined with how infrequently Vue makes breaking API changes to begin with, arguably makes it best-in-class among JavaScript UI framworks in terms of long-term maintenance (although React is ",{"type":21,"tag":29,"props":5020,"children":5023},{"href":5021,"rel":5022},"https://reactjs.org/blog/2020/10/20/react-v17.html#gradual-upgrades",[93],[5024],{"type":26,"value":5025},"introducing a similar upgrade process",{"type":26,"value":5027}," for the upcoming version 18). It's one of the reasons ",{"type":21,"tag":29,"props":5029,"children":5032},{"href":5030,"rel":5031},"https://artandlogic.com/2020/02/why-vue/",[93],[5033],{"type":26,"value":5034},"why we recommend Vue",{"type":26,"value":378},{"type":21,"tag":3490,"props":5037,"children":5038},{},[5039],{"type":26,"value":3494},{"title":8,"searchDepth":254,"depth":254,"links":5041},[5042,5043,5044,5045],{"id":4471,"depth":244,"text":4474},{"id":4573,"depth":244,"text":4576},{"id":4641,"depth":244,"text":4644},{"id":4915,"depth":244,"text":4918},"content:phendry:2021-06:SmoothUpgradesToVue3.md","phendry/2021-06/SmoothUpgradesToVue3.md","phendry/2021-06/SmoothUpgradesToVue3",{"user":4271,"name":4272},{"_path":5051,"_dir":5052,"_draft":7,"_partial":7,"_locale":8,"title":5053,"description":5054,"excerpt":5055,"publishDate":5056,"image":5057,"tags":5058,"body":5059,"_type":3511,"_id":5653,"_source":3513,"_file":5654,"_stem":5655,"_extension":3516,"author":5656},"/ckeefer/2020-1/why-vue","2020-1","Why Vue","Why choose Vue over any other front-end framework?","For web development, when all other considerations are equal, we recommend choosing Vue. Here’s why:","2020-01-01","/ckeefer/2020-1/img/vue-wall.jpg",[12,13],{"type":18,"children":5060,"toc":5607},[5061,5074,5080,5086,5091,5097,5119,5142,5146,5151,5156,5161,5166,5171,5176,5182,5187,5192,5197,5210,5216,5221,5226,5231,5245,5250,5256,5261,5266,5271,5303,5325,5331,5336,5341,5346,5357,5371,5377,5382,5387,5392,5397,5411,5416,5422,5427,5432,5437,5451,5474,5480,5485,5490,5495,5517,5523,5528,5533,5538,5543,5553,5563,5569,5574,5579,5584],{"type":21,"tag":22,"props":5062,"children":5063},{},[5064,5066,5072],{"type":26,"value":5065},"For web development, when all other considerations are equal, we recommend choosing ",{"type":21,"tag":29,"props":5067,"children":5070},{"href":5068,"rel":5069},"https://www.google.com/url?q=https://vuejs.org/&sa=D&ust=1579208471588000",[93],[5071],{"type":26,"value":3962},{"type":26,"value":5073},". Here’s why:",{"type":21,"tag":3699,"props":5075,"children":5077},{"id":5076},"excellent-documentation",[5078],{"type":26,"value":5079},"Excellent Documentation",{"type":21,"tag":51,"props":5081,"children":5083},{"id":5082},"executive-summary",[5084],{"type":26,"value":5085},"Executive Summary",{"type":21,"tag":22,"props":5087,"children":5088},{},[5089],{"type":26,"value":5090},"High quality documentation leads to better results - less time is spent wrestling with the framework or head-scratching about why something is working the way it is, and more time is spent making your project its best.",{"type":21,"tag":51,"props":5092,"children":5094},{"id":5093},"more-details",[5095],{"type":26,"value":5096},"More Details",{"type":21,"tag":22,"props":5098,"children":5099},{},[5100,5102,5109,5111,5118],{"type":26,"value":5101},"The Vue documentation is well written, comprehensive, and instructive. In addition to a ",{"type":21,"tag":29,"props":5103,"children":5106},{"href":5104,"rel":5105},"https://www.google.com/url?q=https://vuejs.org/v2/guide/&sa=D&ust=1579208471590000",[93],[5107],{"type":26,"value":5108},"Guide",{"type":26,"value":5110}," which introduces the various concepts of Vue with helpful examples, looking under the hood is encouraged and supported via a full documentation of the ",{"type":21,"tag":29,"props":5112,"children":5115},{"href":5113,"rel":5114},"https://www.google.com/url?q=https://vuejs.org/v2/api/&sa=D&ust=1579208471590000",[93],[5116],{"type":26,"value":5117},"API",{"type":26,"value":378},{"type":21,"tag":22,"props":5120,"children":5121},{},[5122,5124,5131,5133,5140],{"type":26,"value":5123},"Vue then goes the extra mile by providing a ",{"type":21,"tag":29,"props":5125,"children":5128},{"href":5126,"rel":5127},"https://www.google.com/url?q=https://vuejs.org/v2/style-guide/&sa=D&ust=1579208471591000",[93],[5129],{"type":26,"value":5130},"style guide",{"type":26,"value":5132}," which, for an organization which already has an established style guide (",{"type":21,"tag":29,"props":5134,"children":5137},{"href":5135,"rel":5136},"https://styleguide.artandlogic.com",[93],[5138],{"type":26,"value":5139},"as we do at A+L",{"type":26,"value":5141},"), is most useful in illuminating certain potential pitfalls when working with Vue, as well as providing some simple examples and recipes.",{"type":21,"tag":3699,"props":5143,"children":5144},{"id":3753},[5145],{"type":26,"value":3630},{"type":21,"tag":51,"props":5147,"children":5149},{"id":5148},"executive-summary-1",[5150],{"type":26,"value":5085},{"type":21,"tag":22,"props":5152,"children":5153},{},[5154],{"type":26,"value":5155},"Vue can help eliminate some common patterns of code that lead to poor performance, making your application faster and more responsive.",{"type":21,"tag":51,"props":5157,"children":5159},{"id":5158},"more-details-1",[5160],{"type":26,"value":5096},{"type":21,"tag":22,"props":5162,"children":5163},{},[5164],{"type":26,"value":5165},"Vue uses a virtual DOM implementation. There’s a great deal to be said on this topic, and this should be considered an extremely pared-down summary.",{"type":21,"tag":22,"props":5167,"children":5168},{},[5169],{"type":26,"value":5170},"While reading and writing to the real DOM is a fast and inexpensive operation, the knock-on effects – layout re-calculation and repainting – are slow and expensive operations. Vue, by using a virtual DOM and efficient diffing algorithm, updates as little of the real DOM as possible, and batches such updates, to allow for the minimum of costly knock-on effects, improving rendering time and responsiveness.",{"type":21,"tag":22,"props":5172,"children":5173},{},[5174],{"type":26,"value":5175},"While directly manipulating the DOM can be faster if done carefully and correctly, in practice the dreaded WRW (Write-Read-Write) anti-pattern is all too common, leading to multiple costly repaints. A virtual DOM eliminates this issue.",{"type":21,"tag":3699,"props":5177,"children":5179},{"id":5178},"reactive",[5180],{"type":26,"value":5181},"Reactive",{"type":21,"tag":51,"props":5183,"children":5185},{"id":5184},"executive-summary-2",[5186],{"type":26,"value":5085},{"type":21,"tag":22,"props":5188,"children":5189},{},[5190],{"type":26,"value":5191},"A reactive framework automatically handles some of the work of keeping the UI up-to-date with new values, allowing your project’s developers to focus on business logic rather than presentation.",{"type":21,"tag":51,"props":5193,"children":5195},{"id":5194},"more-details-2",[5196],{"type":26,"value":5096},{"type":21,"tag":22,"props":5198,"children":5199},{},[5200,5202,5208],{"type":26,"value":5201},"Like the React framework before it, Vue is ",{"type":21,"tag":29,"props":5203,"children":5206},{"href":5204,"rel":5205},"https://www.google.com/url?q=https://vuejs.org/v2/guide/reactivity.html&sa=D&ust=1579208471595000",[93],[5207],{"type":26,"value":5178},{"type":26,"value":5209},". This means that, with a little setup work, changing values in JS can create seamless, effortless changes within the UI that relies on those values. Instead of needing to imperatively manipulate the DOM to make updates, simply change the reactive property, and the node that relies on it will be re-rendered with the updated value in place.",{"type":21,"tag":3699,"props":5211,"children":5213},{"id":5212},"progressive",[5214],{"type":26,"value":5215},"Progressive",{"type":21,"tag":51,"props":5217,"children":5219},{"id":5218},"executive-summary-3",[5220],{"type":26,"value":5085},{"type":21,"tag":22,"props":5222,"children":5223},{},[5224],{"type":26,"value":5225},"You can begin integrating Vue into your existing project right away and begin experiencing its benefits, without needing to change the way the whole application works all at once.",{"type":21,"tag":51,"props":5227,"children":5229},{"id":5228},"more-details-3",[5230],{"type":26,"value":5096},{"type":21,"tag":22,"props":5232,"children":5233},{},[5234,5236,5243],{"type":26,"value":5235},"Vue is fairly lightweight, and can be attached to a single given DOM node, even using the existing DOM structure as it’s template if it finds one, allowing Vue to take over an existing page and ",{"type":21,"tag":29,"props":5237,"children":5240},{"href":5238,"rel":5239},"https://www.google.com/url?q=https://en.wikipedia.org/wiki/Progressive_enhancement&sa=D&ust=1579208471598000",[93],[5241],{"type":26,"value":5242},"progressively enhance",{"type":26,"value":5244}," it.",{"type":21,"tag":22,"props":5246,"children":5247},{},[5248],{"type":26,"value":5249},"This makes it a good candidate not just as the backbone of a new project, but also for introducing into an existing project to offer enhanced functionality in one small area of the application and slowly expanding from there.",{"type":21,"tag":3699,"props":5251,"children":5253},{"id":5252},"extensible",[5254],{"type":26,"value":5255},"Extensible",{"type":21,"tag":51,"props":5257,"children":5259},{"id":5258},"executive-summary-4",[5260],{"type":26,"value":5085},{"type":21,"tag":22,"props":5262,"children":5263},{},[5264],{"type":26,"value":5265},"Vue has a thriving ecosystem containing many elements that can be added to your application to add new functionality; and Vue is flexible enough to allow your developers to extend and enhance the way it works.",{"type":21,"tag":51,"props":5267,"children":5269},{"id":5268},"more-details-4",[5270],{"type":26,"value":5096},{"type":21,"tag":22,"props":5272,"children":5273},{},[5274,5276,5283,5285,5292,5294,5301],{"type":26,"value":5275},"Vue focuses on, as the name suggests, the view aspect of the familiar MVC model (although Vue actually subscribes to the ",{"type":21,"tag":29,"props":5277,"children":5280},{"href":5278,"rel":5279},"https://www.google.com/url?q=https://en.wikipedia.org/wiki/Model%25E2%2580%2593view%25E2%2580%2593viewmodel&sa=D&ust=1579208471600000",[93],[5281],{"type":26,"value":5282},"MVVM pattern",{"type":26,"value":5284},"). Other modules within the Vue ecosystem focus on routing (",{"type":21,"tag":29,"props":5286,"children":5289},{"href":5287,"rel":5288},"https://www.google.com/url?q=https://router.vuejs.org/&sa=D&ust=1579208471600000",[93],[5290],{"type":26,"value":5291},"Vue-Router",{"type":26,"value":5293},"), state management (",{"type":21,"tag":29,"props":5295,"children":5298},{"href":5296,"rel":5297},"https://www.google.com/url?q=https://vuex.vuejs.org/&sa=D&ust=1579208471601000",[93],[5299],{"type":26,"value":5300},"Vuex",{"type":26,"value":5302},"), and extend Vue.",{"type":21,"tag":22,"props":5304,"children":5305},{},[5306,5308,5315,5317,5324],{"type":26,"value":5307},"There are ",{"type":21,"tag":29,"props":5309,"children":5312},{"href":5310,"rel":5311},"https://www.google.com/url?q=https://github.com/vuejs/awesome-vue&sa=D&ust=1579208471602000",[93],[5313],{"type":26,"value":5314},"many other Vue plugins",{"type":26,"value":5316}," within a healthy developer ecosystem, and creating your own plugins is ",{"type":21,"tag":29,"props":5318,"children":5321},{"href":5319,"rel":5320},"https://www.google.com/url?q=https://vuejs.org/v2/guide/plugins.html&sa=D&ust=1579208471602000",[93],[5322],{"type":26,"value":5323},"easy and well documented",{"type":26,"value":378},{"type":21,"tag":3699,"props":5326,"children":5328},{"id":5327},"single-file-components",[5329],{"type":26,"value":5330},"Single File Components",{"type":21,"tag":51,"props":5332,"children":5334},{"id":5333},"executive-summary-5",[5335],{"type":26,"value":5085},{"type":21,"tag":22,"props":5337,"children":5338},{},[5339],{"type":26,"value":5340},"Vue supports organizing structure, logic and styling together in the same file, enabling better organization of your application’s code that leads to less time wasted tracking down what piece of code is doing what in your project.",{"type":21,"tag":51,"props":5342,"children":5344},{"id":5343},"more-details-5",[5345],{"type":26,"value":5096},{"type":21,"tag":22,"props":5347,"children":5348},{},[5349,5355],{"type":21,"tag":29,"props":5350,"children":5353},{"href":5351,"rel":5352},"https://www.google.com/url?q=https://vuejs.org/v2/guide/single-file-components.html&sa=D&ust=1579208471604000",[93],[5354],{"type":26,"value":5330},{"type":26,"value":5356}," are useful units for organizing the structure, logic and styling of a reusable component into an atomic form, and make it much easier to reason about the operation and composition of a given component compared to a more traditional approach. Separation of concerns is maintained without requiring the elements of a given component to be spread across many different files.",{"type":21,"tag":22,"props":5358,"children":5359},{},[5360,5362,5369],{"type":26,"value":5361},"This approach borrows many of the best ideas of the standardized ",{"type":21,"tag":29,"props":5363,"children":5366},{"href":5364,"rel":5365},"https://www.google.com/url?q=https://developer.mozilla.org/en-US/docs/Web/Web_Components&sa=D&ust=1579208471605000",[93],[5367],{"type":26,"value":5368},"Web Components",{"type":26,"value":5370},", without that standard’s compatibility limitations.",{"type":21,"tag":3699,"props":5372,"children":5374},{"id":5373},"familiar-templates",[5375],{"type":26,"value":5376},"Familiar Templates",{"type":21,"tag":51,"props":5378,"children":5380},{"id":5379},"executive-summary-6",[5381],{"type":26,"value":5085},{"type":21,"tag":22,"props":5383,"children":5384},{},[5385],{"type":26,"value":5386},"By using HTML and related familiar syntax, your project’s developers can start writing readable, easily understood application structure from day one.",{"type":21,"tag":51,"props":5388,"children":5390},{"id":5389},"more-details-6",[5391],{"type":26,"value":5096},{"type":21,"tag":22,"props":5393,"children":5394},{},[5395],{"type":26,"value":5396},"In place of React’s JSX, or yet another DSL, Vue allows you to use the familiar syntax of HTML in your templates. Similar to angular, directives live as attributes on your elements, and custom elements can be declared, imported and used like standard html tags. It’s elegant and effective.",{"type":21,"tag":22,"props":5398,"children":5399},{},[5400,5402,5409],{"type":26,"value":5401},"And if you’re a fan of ",{"type":21,"tag":29,"props":5403,"children":5406},{"href":5404,"rel":5405},"https://www.google.com/url?q=https://pugjs.org/api/getting-started.html&sa=D&ust=1579208471607000",[93],[5407],{"type":26,"value":5408},"Pug",{"type":26,"value":5410},", you can use that instead (or in addition to) your HTML templates, eliminating the verbosity of HTML without losing any of the familiar syntax.",{"type":21,"tag":22,"props":5412,"children":5413},{},[5414],{"type":26,"value":5415},"Vue does allow falling back to directly writing render functions, if for some reason your use case requires it, as well as supporting JSX if desired.",{"type":21,"tag":3699,"props":5417,"children":5419},{"id":5418},"integrated-toolchain",[5420],{"type":26,"value":5421},"Integrated Toolchain",{"type":21,"tag":51,"props":5423,"children":5425},{"id":5424},"executive-summary-7",[5426],{"type":26,"value":5085},{"type":21,"tag":22,"props":5428,"children":5429},{},[5430],{"type":26,"value":5431},"Vue comes packaged with a suite of tools that give your project’s developers a hand in getting your application code built and running, boosting productivity.",{"type":21,"tag":51,"props":5433,"children":5435},{"id":5434},"more-details-7",[5436],{"type":26,"value":5096},{"type":21,"tag":22,"props":5438,"children":5439},{},[5440,5442,5449],{"type":26,"value":5441},"In order to take advantage of some of the features of Vue, you need a toolchain to build the scripts, extract the various components, and tie everything together. Vue comes with toolchain support out-of-the-box via the ",{"type":21,"tag":29,"props":5443,"children":5446},{"href":5444,"rel":5445},"https://www.google.com/url?q=https://cli.vuejs.org/&sa=D&ust=1579208471609000",[93],[5447],{"type":26,"value":5448},"vue-cli",{"type":26,"value":5450},", which even provides a limited web-based GUI for customizing certain aspects of your project and adding community-provided plugins.",{"type":21,"tag":22,"props":5452,"children":5453},{},[5454,5456,5463,5465,5472],{"type":26,"value":5455},"Under the hood, vue-cli relies on ",{"type":21,"tag":29,"props":5457,"children":5460},{"href":5458,"rel":5459},"https://www.google.com/url?q=https://webpack.js.org/&sa=D&ust=1579208471610000",[93],[5461],{"type":26,"value":5462},"webpack",{"type":26,"value":5464},", and ",{"type":21,"tag":29,"props":5466,"children":5469},{"href":5467,"rel":5468},"https://www.google.com/url?q=https://cli.vuejs.org/guide/webpack.html&sa=D&ust=1579208471611000",[93],[5470],{"type":26,"value":5471},"provides guidance and tools",{"type":26,"value":5473}," for interacting with it if the standard configuration isn’t sufficient for your project’s needs.",{"type":21,"tag":3699,"props":5475,"children":5477},{"id":5476},"cross-platform-support",[5478],{"type":26,"value":5479},"Cross-Platform Support",{"type":21,"tag":51,"props":5481,"children":5483},{"id":5482},"executive-summary-8",[5484],{"type":26,"value":5085},{"type":21,"tag":22,"props":5486,"children":5487},{},[5488],{"type":26,"value":5489},"Vue can be used to create native mobile applications, and take advantage of the functionality of the platform that might not be available to web applications, like the accelerometer or push notifications.",{"type":21,"tag":51,"props":5491,"children":5493},{"id":5492},"more-details-8",[5494],{"type":26,"value":5096},{"type":21,"tag":22,"props":5496,"children":5497},{},[5498,5500,5507,5509,5515],{"type":26,"value":5499},"Via ",{"type":21,"tag":29,"props":5501,"children":5504},{"href":5502,"rel":5503},"https://www.google.com/url?q=https://vue-native.io/&sa=D&ust=1579208471613000",[93],[5505],{"type":26,"value":5506},"Vue Native",{"type":26,"value":5508},", developing cross-platform mobile applications using Vue is straightforward and powerful. Under the hood, Vue Native is really ",{"type":21,"tag":29,"props":5510,"children":5513},{"href":5511,"rel":5512},"https://www.google.com/url?q=https://vue-native.io/docs/index.html%23What-is-Vue-Native&sa=D&ust=1579208471613000",[93],[5514],{"type":26,"value":3945},{"type":26,"value":5516},", providing a wrapper around the latter’s APIs, so all of the same Pros and Cons that apply to React Native apply here, with the significant pro that the continued development on React Native directly benefits the Vue Native platform as well.",{"type":21,"tag":3699,"props":5518,"children":5520},{"id":5519},"widely-used",[5521],{"type":26,"value":5522},"Widely Used",{"type":21,"tag":51,"props":5524,"children":5526},{"id":5525},"executive-summary-9",[5527],{"type":26,"value":5085},{"type":21,"tag":22,"props":5529,"children":5530},{},[5531],{"type":26,"value":5532},"Vue is widely used in web application development. Using technologies that are widely accepted reduces future project risks that components will not continue to be maintained or accessing knowledgeable developers for maintenance will become prohibitively expensive or difficult.",{"type":21,"tag":51,"props":5534,"children":5536},{"id":5535},"more-details-9",[5537],{"type":26,"value":5096},{"type":21,"tag":22,"props":5539,"children":5540},{},[5541],{"type":26,"value":5542},"Companies like Gitlab, Nintendo, Facebook and Netflix make use of  Vue in their development toolset.",{"type":21,"tag":22,"props":5544,"children":5545},{},[5546],{"type":21,"tag":29,"props":5547,"children":5550},{"href":5548,"rel":5549},"https://www.google.com/url?q=https://www.netguru.com/blog/13-top-companies-that-have-trusted-vue.js-examples-of-applications&sa=D&ust=1579208471615000",[93],[5551],{"type":26,"value":5552},"https://www.netguru.com/blog/13-top-companies-that-have-trusted-vue.js-examples-of-applications",{"type":21,"tag":22,"props":5554,"children":5555},{},[5556],{"type":21,"tag":29,"props":5557,"children":5560},{"href":5558,"rel":5559},"https://www.google.com/url?q=https://www.techuz.com/blog/top-9-websites-built-using-vue-js/&sa=D&ust=1579208471616000",[93],[5561],{"type":26,"value":5562},"https://www.techuz.com/blog/top-9-websites-built-using-vue-js/",{"type":21,"tag":3699,"props":5564,"children":5566},{"id":5565},"open-source",[5567],{"type":26,"value":5568},"Open Source",{"type":21,"tag":51,"props":5570,"children":5572},{"id":5571},"executive-summary-10",[5573],{"type":26,"value":5085},{"type":21,"tag":22,"props":5575,"children":5576},{},[5577],{"type":26,"value":5578},"Using an open source technology eliminates the future risk that a vendor will change licensing terms or go out of business which could lead to unexpected costs to transition to a different technology.",{"type":21,"tag":51,"props":5580,"children":5582},{"id":5581},"more-details-10",[5583],{"type":26,"value":5096},{"type":21,"tag":22,"props":5585,"children":5586},{},[5587,5589,5596,5598,5605],{"type":26,"value":5588},"Vue is ",{"type":21,"tag":29,"props":5590,"children":5593},{"href":5591,"rel":5592},"https://www.google.com/url?q=https://github.com/vuejs/vuejs.org/blob/master/LICENSE&sa=D&ust=1579208471618000",[93],[5594],{"type":26,"value":5595},"MIT licensed",{"type":26,"value":5597},".The ",{"type":21,"tag":29,"props":5599,"children":5602},{"href":5600,"rel":5601},"https://www.google.com/url?q=https://opensource.org/licenses/MIT&sa=D&ust=1579208471618000",[93],[5603],{"type":26,"value":5604},"MIT License",{"type":26,"value":5606}," is one of the most permissive open source licenses, allowing you to transform the original source, bundle it with your own application in any form, and does not require open sourcing the resulting application. The only requirement is to include the license and copyright notice originally bundled with the source code, making software under this license an excellent choice for inclusion in commercial products.",{"title":8,"searchDepth":254,"depth":254,"links":5608},[5609,5613,5617,5621,5625,5629,5633,5637,5641,5645,5649],{"id":5076,"depth":244,"text":5079,"children":5610},[5611,5612],{"id":5082,"depth":254,"text":5085},{"id":5093,"depth":254,"text":5096},{"id":3753,"depth":244,"text":3630,"children":5614},[5615,5616],{"id":5148,"depth":254,"text":5085},{"id":5158,"depth":254,"text":5096},{"id":5178,"depth":244,"text":5181,"children":5618},[5619,5620],{"id":5184,"depth":254,"text":5085},{"id":5194,"depth":254,"text":5096},{"id":5212,"depth":244,"text":5215,"children":5622},[5623,5624],{"id":5218,"depth":254,"text":5085},{"id":5228,"depth":254,"text":5096},{"id":5252,"depth":244,"text":5255,"children":5626},[5627,5628],{"id":5258,"depth":254,"text":5085},{"id":5268,"depth":254,"text":5096},{"id":5327,"depth":244,"text":5330,"children":5630},[5631,5632],{"id":5333,"depth":254,"text":5085},{"id":5343,"depth":254,"text":5096},{"id":5373,"depth":244,"text":5376,"children":5634},[5635,5636],{"id":5379,"depth":254,"text":5085},{"id":5389,"depth":254,"text":5096},{"id":5418,"depth":244,"text":5421,"children":5638},[5639,5640],{"id":5424,"depth":254,"text":5085},{"id":5434,"depth":254,"text":5096},{"id":5476,"depth":244,"text":5479,"children":5642},[5643,5644],{"id":5482,"depth":254,"text":5085},{"id":5492,"depth":254,"text":5096},{"id":5519,"depth":244,"text":5522,"children":5646},[5647,5648],{"id":5525,"depth":254,"text":5085},{"id":5535,"depth":254,"text":5096},{"id":5565,"depth":244,"text":5568,"children":5650},[5651,5652],{"id":5571,"depth":254,"text":5085},{"id":5581,"depth":254,"text":5096},"content:ckeefer:2020-1:Why Vue.md","ckeefer/2020-1/Why Vue.md","ckeefer/2020-1/Why Vue",{"user":3518,"name":3519},1780330265138]