summaryrefslogtreecommitdiff
path: root/vue-notes.md
blob: 1c966555626604887fe8da9466375a2dd8ce2943 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
---
LocalWords: Vue DOM JS
title: "LukeShu's Guide to Vue"
author:
 - Luke T. Shumaker
abstract: |
  There are 4 primary pieces to the official Vue documentation:

   1. Guide
   2. API
   3. Style Guide
   4. Examples

  The "Guide" is where concepts get introduced and explained; but fairly
  little of the underlying machinery or details are explained; or it is
  hard to find.  The "API" is where the machinery and details are
  explained, but the concepts of how that fits together is missing; it
  links to the Guide.

  I think it's silly that those are 2 separate documents.
---

# Introduction

	import Vue from 'vue';

Vue (pronounced like "view") is a *progressive* framework for building
user interfaces; progressive means that you can use it for as much, or
as little, of the user interface as you like.

There are a few major object types in Vue that are helpful to
understanding Vue at a high-level:

 - *Vue Instances*: a Vue instance manages a part of the DOM.

 - *Components*: think of components as "custom HTML `<element>`s".
   An instance of a component is a type of Vue instance.  That is,
   your custom `<element>` obviously "owns" and manages the underlying
   real HTML elements in the DOM that are used to implement it.

 - *Directives*: think of directives as "custom HTML `attr="ibutes"`".

In addition to those objects:

 - *Reactive*: Each *component* has a "data" object associated with
   it; this is usually just a plain map Object.  If you (in the
   ordinary, plain, JS ways!) modify that object, the component will
   automatically *react* to that change, and update the DOM
   accordingly.

 - *Templates*: Vue has its own HTML templating language, that allows
   us to write markup such that Vue knows how to make it *reactive*.
   It's just plain HTML, but with (1) Vue-defined and user-defined
   custom elements (via *components*), and (2) Vue-defined and
   user-defined custom attributes (via *directives*).  If you don't
   like writing raw HTML, that's fine, you could write it via PUG or
   any other compile-to-HTML language, since Vue templates are *just
   HTML*.  From the JavaScript, they are just plain strings.

 - *Render functions*: Ultimately, *templates* compile to render
   functions.  If your application design and toolchain
   (WebPack/Babel/what-have-you) allow it, this can be done
   ahead-of-time as a server-side optimization step before being
   served to the client, or it can happen at runtime by calling
   `Vue.compile("template string")`, which returns a function.
   Actually, the compiler returns a `render` function *and* a set of
   `staticRenderFns` helpers.  Anyway, having render functions exposed
   to programmers means that, if you want, you can write the render
   functions yourself, instead of writing templates.  Programmers
   coming from React will note that JSX is useful for writing render
   functions.

Tying it together: A *component* is mostly just a *Vue instance* that
manages its part of the DOM by calling a *render function* (compiled
from a *template*) in accordance with an object that the component is
assigned to be *reactive* to.

The premise of Vue is that this small set of objects and concepts
gives us the tools to effectively write dope-ass parts of a
user-interface, without requiring is to use Vue to do the entire
interface (though you could).

# Major topics

## Reactivity

Because of limitations in JavaScript, when implementing the magical
reactivity that Vue provides, Vue can detect attribute *modification*,
but not adding or removing attributes.  Lame!  So, Vue provides us
with a couple of silly magic functions to work around this limitation:

 - `Vue.set(object, key, value);` is like `object[key] = value;`, except
   that if the `key` attribute doesn't exist yet, it is created as a
   reactive attribute, working around the limitation that Vue can't
   detect attribute additions.
   
 - `Vue.delete(object, key);` is like `delete object[key];`, but
   ensures that the deletion triggers view updates, working around the
   limitation that Vue can't detect attribute deletions.

## Root Vue Instance

	var vm = new Vue({ ... });
	
> As a convention, it is common to use the variable name `vm` for the
> root Vue instance; `vm` stands for ViewModel; a reference to the
> [Model+View+ViewModel (MVVM)][MVVM] application architecture; but
> don't worry about MVVM, since from your point of view of, your Vue
> program won't be following MVVM; just accept it as an arbitrary
> convention.

To use it, you will need to *mount* the instance to the part of the
DOM that it will manage.

You can do this after-the-fact like:

	vm.$mount("css-selector"); // the first matching element will be used
	// or
	vm.$mount(HTMLElement);

Or, you can do it at instance creation by specifying `el`:

	var vm = new Vue({
		el: CSS-selector-or-HTMLElement,
	});

The mount-point element will be *replaced* with the Vue-generated DOM,
so it is therefore not recommended to mount the root instance to
`<html>` or `<body>`.

## Components

We define a component like

	var MyComponent = Vue.extend({ ... });

The things that go in the `...` are a superset of the things that we
can pass to `new Vue({ ... })`.

But that doesn't give it a name!  We'll need to register our component
with an HTML tag name.

### Global registration

We register a component globally with:

	Vue.component('tag-name', MyComponent);
	
 > Vue does not enforce the rules on component names that are there
 > for [W3C Custom Element][W3C Custom Elements] tag names
 > (all-lowercase, must contain a hyphen), but it is conventional to
 > follow them anyway, and is considered good practice.

Since it's so common to immediately register components, and not
otherwise use them directly in the JS, we have a bit of shorthand that
we can use for convenience:

	Vue.component('tag-name', Vue.extend({ ... }));
	// can be written as
	Vue.component('tag-name', { ... });
	// and it will automatically call Vue.extend for us

 > Wait, that didn't actually save us much typing, and obscured the
 > fact that component creation and registration are two distinct
 > operations.  Lame shorthand!
 
If we want to be able to retrieve a component that we know is
registered, but the current code doesn't have an object for, we can
get it like:
 
	// returns the component previously registered to 'tag-name'
	var MyComponent = Vue.component('tag-name'); 

### Scoped registration

Of course, you may have had drilled in to your head "globals are
bad".  We can also register components locally to a Vue instance.

TODO.

## Directives

Unlike components, which are a specific object type that had to be
created with `Vue.extend(...)`, directives are implemented as plain
map objects.

Which is a little confusing, since it means that directive
registration looks like directive creation, and puts wrong notions in
your head.

### Global registration

Anyway, a directive can be registered globally:

	Vue.directive('directive-name', { ... });

The resulting attribute name always has a `v-` prefix; the above
results in needing to set `v-directive-name="foo"`.

### Scoped registration

TODO

## Mixins

## Templates

 > Unfortunately, that's custom `<element></element>`s; with Vue
 > components, we can't use the `<element />` shorthand, or
 > implied-closing (like with `<li>`).

# Built-in ("core") directives

TODO

# Configuration

 - Global: `Vue.config`
   * Development Settings
     * `Vue.config.silent` Bool
     * `Vue.config.devtools` Bool
	 * `Vue.config.warnHandler` Function
     * `Vue.config.performance` Bool
     * `Vue.config.productionTip` Bool
   * For-reals Settings
     * `Vue.config.optionMergeStrategies` Map<String,Function>
     * `Vue.config.errorHandler` Function
     * `Vue.config.ignoredElements` Array<String|RegExp>
	 * `Vue.config.keyCodes` Map<String,Number|Array<Number>>

# Bonus: Single File Components (SFC's)

TODO

Once upon a time, there was library that compiled SFCs in to JS
modules (`vue-component-compiler`); there were a couple of 3rd-party
stand-alone CLI wrappers for it.  That compiler got merged in to
`vueify` (the Browserify plugin for SFCs), and even though the
compiler API is still exposed there, other bundler plugins don't share
it.  There's a new `vue-component-compiler` being developed, but it's
not ready yet.  That means we're left with 3 *separate* SFC
"compilers" that are fairly tightly coupled with the bundle system
they're designed for.  I'm sure they don't contain any nasty
differences.

 - WebPack (`vue-loader`): Presumed to be the flagship option.

 - Browserify (`vueify`): Vue 2.5.0 (2017-10-12) added the ability to
   write Functional Components as SFCs.  That is not yet supported in
   Vueify.  Three months isn't a long time, but we can surmise that
   Vueify is the ugly step child now.

 - Rollup (`rollup-plugin-vue`): TODO

The resulting JS module does 2 things:
 - Inject global CSS in to the page (at module load)
    * vue-loader: TODO
    * vueify: `require("vueify/lib/insert-css").insert("CSS-string")`
    * rollup-plugin-vue: TODO
 - Export an object suitable to pass to `Vue.component()`; either a
   raw `Object`, or a `Vue.extend()`-blessed object (which has type
   `Function`)

   This is mostly is up to you, exporting it in the `<script>`
   element.  However, this obviously doesn't include the template.
   How does it inject the template in to the object you export, when
   there are (1) multiple object formats that you can export, and (2)
   multiple module syntaxes that you can use to export it?
    * vue-loader: TODO
    * vueify: (2) Assume Node module syntax (CommonJS-ish), and (2)
      set:

          var tmp_options = typeof module.exports === "function" ? module.exports.options : module.exports;
          tmp_options.render = function() { ... };
		  tmp_options.staticRenderFns = ...;

    * rollup-plugin-vue: TODO

# misc

Components don't work by literally registering custom elements with
the browser (though a W3C spec exists for allowing that, it isn't
(yet?) widely implemented).  Instead, it's the *template language*
that knows about them, the custom element names are registered with
the template compiler, and the compiler then knows that when it
encounters a node with that element name, it needs to emit a render
function that instantiates that component.  Ditto for directives.

THE ABOVE IS FALSE.  The render function calls
`something.createElement("element-name")`, the components are
registered with the `createElement`; the compiler doesn't need to know
this.

I'm a big advocate of learning about things by reading the source.  Be
aware that Vue is written in a JavaScript superset language called
[Flow][] that adds typechecking, similar to TypeScript.  When reading
the official docs, their notation for types seemed a little weird to
me; it seemed that Java-like notation would have more intuitively
conveyed a few constructs--until I realized that they were using Flow
notation.

 * Global API
   - `Vue.nextTick`
   - `Vue.filter`
   - `Vue.use` (plugins)
   - `Vue.mixin`

   - `Vue.version` return the Vue version as a String

Vue instances may have a "render" function, or a "template".  I
believe that templates compile to a render function (via
`vue-template-compiler`), either at run-time, or at bundle-time if
possible.

# options

[MVVM]: https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel
[W3C Custom Elements]: https://www.w3.org/TR/custom-elements/#concepts
[Flow]: https://flow.org/