├── .editorconfig ├── .eslintrc ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── nwb.config.js ├── package-lock.json ├── package.json ├── src ├── convertBindingsToObject.js ├── convertDataToObject.js ├── createAppData.js ├── createAppTemplate.js ├── createComponentTemplates.js ├── index.js └── utils │ ├── arrayFrom.js │ └── objectAssign.js ├── tasks └── remove-umd-default.js └── tests ├── .eslintrc └── index-test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*.{css,html,js,scss}] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "parserOptions": { 4 | "ecmaVersion": 6, 5 | "sourceType": "module" 6 | }, 7 | "env": { 8 | "amd": true, 9 | "browser": true 10 | }, 11 | "globals": { 12 | "module": true, 13 | }, 14 | "extends": "eslint:recommended", 15 | "rules": { 16 | "arrow-parens": 2, 17 | "brace-style": [2, "stroustrup"], 18 | "indent": [2, 2], 19 | "no-else-return": 2, 20 | "semi": [2, "always"], 21 | "space-before-function-paren": [2, "always"] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /coverage 2 | /demo/dist 3 | /es 4 | /lib 5 | /node_modules 6 | /umd 7 | npm-debug.log* 8 | .DS_Store 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: node_js 4 | node_js: 5 | - 6 6 | 7 | branches: 8 | only: 9 | - master 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Prerequisites 2 | 3 | [Node.js](http://nodejs.org/) >= v4 must be installed. 4 | 5 | ## Installation 6 | 7 | - Running `npm install` in the module's root directory will install everything you need for development. 8 | 9 | ## Building 10 | 11 | - `npm run build` will build the module for publishing to npm. 12 | 13 | - `npm run clean` will delete built resources. 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Matt Stow 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Quench Vue logo 3 |

4 | 5 | Travis build status 6 | 7 | 8 | npm package 9 | 10 |
11 |

12 | 13 | # Quench Vue 14 | 15 | **Simple, tiny, client-side hydration of pre-rendered [Vue.js](https://vuejs.org) apps** 16 | 17 | Quench Vue allows server-rendered/static markup to be used as a Vue app's `data`, `template` and local components' `template`s. It's great for when you can't/don't want to use "real" [server-side rendering](https://vuejs.org/v2/guide/ssr.html). 18 | 19 | All of Vue's existing features will work as normal when the app is initialised in the browser. 20 | 21 | ## Table of Contents 22 | 23 | - [Demo](#demo) 24 | - [Installation](#installation) 25 | - [npm](#npm) 26 | - [Direct ` 75 | ``` 76 | 77 | *Note: You will need to use [the full build of Vue.js](https://vuejs.org/v2/guide/installation.html#Explanation-of-Different-Builds), which includes the compiler.* 78 | 79 | ## Usage 80 | 81 | 1. [Defining the app `data` and `template`](#defining-the-app-data-and-template). 82 | 2. [Defining local component `template`s](#defining-local-component-templates). 83 | 84 | ## Defining the app `data` and `template` 85 | 86 | There are 2 ways of defining and using `data` for the app: 87 | 88 | 1. With a stringified JSON object in the app container's `q-data` attribute; and/or 89 | 2. With an inline `q-binding` attribute on an element, when `q-convert-bindings` is added to the app container. 90 | 91 | Both techniques can be used together or on their own, but the `q-data` is preferred as it's faster, simpler and more versatile. 92 | 93 | Let's look at some examples: 94 | 95 | ### Method 1: Defining the `data` with `[q-data]` 96 | 97 | This method allows you to easily specify the `data` for the app, including arrays and objects. 98 | 99 | ```html 100 |
122 | … 123 |
124 | ``` 125 | 126 | #### Rendering the data with `[v-text]` 127 | 128 | We obviously duplicate the "data" in the markup, and inform Vue which elements are bound to which `data` properties using a [`v-text`](https://vuejs.org/v2/api/#v-text) attribute whose value points to a property name, such as: 129 | 130 | ```html 131 |

Hello, World!

132 |

2018

133 | 134 | 144 | 145 | 155 | 156 | 168 | ``` 169 | 170 | For iterating over lists, we also need to use another syntax, ``, which [we'll describe later](#hiding-elements-from-the-compiler). 171 | 172 | *Note:* 173 | * *You can also use [`v-html`](https://vuejs.org/v2/api/#v-html) to render HTML, but ensure that it's sanitized and trusted.* 174 | * *You only need to output the `v-for` and the `v-text`/`q-binding` attributes on the first iteration of the loop.* 175 | 176 | ### Method 2: Defining the `data` with inline `[q-binding]` bindings 177 | 178 | While we don't recommend the following approach for anything but the simplest of apps, when `q-convert-bindings` is set on the app's container, we can also use the `q-binding` attribute to create a `data` variable that is equal to the value of the element's `.textContent`. 179 | 180 | *Note:* 181 | * *Bindings specified in the global `q-data` object take precedence over inline bindings.* 182 | * *Do not nest elements inside a `q-binding` element, or you'll have unexpected results.* 183 | 184 | The following examples all perfectly re-create the global `q-data` object from before. 185 | 186 | #### Simple bindings 187 | 188 | ```html 189 |
190 |

Hello, World!

191 |

2018

192 |
193 | ``` 194 | 195 | #### Array and Object bindings 196 | 197 | Vue supports iterating over arrays and objects via [the `v-for` directive](https://vuejs.org/v2/guide/list.html) with the syntax `item in items`, where `items` is the source data list and `item` is an **alias** for the array element being iterated on. 198 | 199 | To inline bind with Quench, we need to use another special syntax `itemsSource as item`. 200 | 201 | ##### Array 202 | 203 | To replicate the `tags` array from above, we would: 204 | 205 | ```html 206 |
207 | 217 |
218 | ``` 219 | 220 | where `itemsSource` is the name of the array (`tags`) plus the index in the array `[0]`/`[1]` which we wish to populate, and `tag` is the `item` alias in the `v-for`. 221 | 222 | ##### Object 223 | 224 | To replicate the `author` object from above, we would: 225 | 226 | ```html 227 |
228 | 238 |
239 | ``` 240 | 241 | where `itemsSource` is the name of the object (`author`) plus the relevant object key `.firstName`/`.lastName` which we wish to populate, and `key` is the `item` alias in the `v-for`. 242 | 243 | ##### Array of Objects 244 | 245 | Both of the above techniques can be combined, so to replicate the `skills` array from above, we would: 246 | 247 | ```html 248 |
249 | 261 |
262 | ``` 263 | 264 | where `itemsSource` is the name of the array and index (`skills[0]`) plus the relevant object key `.name`/`.level` which we wish to populate, and `skill.name`/`skill.level` is the `item` alias in the `v-for` plus the object key. 265 | 266 | Hopefully you'll agree that using inline bindings to set the `data` is more complicated than using the `q-data` method, but it can still have its uses. 267 | 268 | *Note: When using inline bindings, arrays and objects are limited to a depth of 1 level.* 269 | 270 | #### Non-element bindings 271 | 272 | Since v0.7.0, you can also create `data` from bindings using specially formatted comments, thus not requiring to have actual elements to attach to. This can be useful if you need to create extra `data` that is "invisible" to the user, or if you need to create more complex values, such as nested arrays and objects. 273 | 274 | Using the syntax `` we can easily recreate the `data` from the previous examples: 275 | 276 | ```html 277 |
278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 |
289 | ``` 290 | 291 | However, we can also create more complex `data` values. The following recreates the above arrays and objects succinctly. 292 | 293 | ```html 294 |
295 | 296 | 297 | 298 |
299 | ``` 300 | 301 | *Note: Non-element bindings must be JSON-serializable and written on one line.* 302 | 303 | ### Referencing global variables as `data` properties 304 | 305 | You can also pass global variables (on `window`) to be used as data properties. Similarly to `q-data`, we can pass a stringified JSON object of key/value pairs to a `q-r-data` attribute, where *key* is the name of the `data`'s property and *value* the name of the global variable to be used, which can also use dot notation to access properties of an object. 306 | 307 | ```html 308 | 316 |
322 | ``` 323 | 324 | which will produce the following `data`: 325 | 326 | ```js 327 | { 328 | env: 'dev', 329 | port: 3000, 330 | foo: 'bar', 331 | baz: 'qux', 332 | } 333 | ``` 334 | 335 | *Note: Bindings specified in the `q-r-data` object take precedence over those in `q-data`.* 336 | 337 | ### Excluding elements from the app template compiler 338 | 339 | In the previous sections, we introduced the `` syntax. These are a pair of opening and closing comments that exclude the contents within from being passed to the template compiler. 340 | 341 | The most obvious use case (and necessary when using inline bindings) is to strip all but the first element of a `v-for` loop as demonstrated earlier. 342 | 343 | Another use case is to replace static markup for a component, such as: 344 | 345 | ```html 346 | 347 |
I will be stripped in the app and "replaced" with the component version below
348 | 349 | 350 | ``` 351 | 352 | *Note: Nesting comments is not supported.* 353 | 354 | ### Instantiating the app 355 | 356 | Very little needs to change from the way you'd normally instantiate an app. 357 | 358 | #### With a module bundler, such as webpack 359 | 360 | ```js 361 | import Vue from 'vue'; 362 | import { createAppData, createAppTemplate } from 'quench-vue'; 363 | 364 | var appEl = document.getElementById('app'); 365 | var data = createAppData(appEl); 366 | var template = createAppTemplate(appEl); 367 | 368 | var app = new Vue({ 369 | el: appEl, 370 | data: data, 371 | template: template, 372 | }); 373 | ``` 374 | 375 | #### For direct ` 379 | 380 | ``` 381 | 382 | ```js 383 | var appEl = document.getElementById('app'); 384 | var data = quenchVue.createAppData(appEl); 385 | var template = quenchVue.createAppTemplate(appEl); 386 | 387 | var app = new Vue({ 388 | el: appEl, 389 | data: data, 390 | template: template, 391 | }); 392 | ``` 393 | 394 | ## Defining local component `template`s 395 | 396 | Vue applications are often comprised of multiple components, which promotes reuse and reduces repetition. However, the more components you have, the greater your JavaScript bundle will be. While complex components, such as interactive UI widgets should probably be defined in JavaScript, simpler, more display-only components can easily be defined from existing, pre-rendered HTML with Quench Vue. 397 | 398 | Defining local component `template`s from existing markup suits situations such as an infinite scroll of news cards, where the original "page" of cards are pre-rendered, and as a user scrolls, your Vue app needs to fetch and append more cards from a JSON API response. 399 | 400 | *Note: You cannot use Quench Vue to specify the `template` of global components created with `Vue.component()`. We consider global components an anti-pattern anyway.* 401 | 402 | ### Specifying a component with `[q-component]` 403 | 404 | Any element within your app's `el` can be used as the markup for a component by adding an attribute of `q-component="NAME"`, where `"NAME"` is the name of the local component defined in your Vue app. 405 | 406 | Typically, this would be on a `
` or similar, which sets the `outerHTML` of the element to be used as the `template`. However, you can also use a `