• Stars
    star
    8,689
  • Rank 3,972 (Top 0.09 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created almost 3 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

6kb subset of Vue optimized for progressive enhancement

petite-vue

petite-vue is an alternative distribution of Vue optimized for progressive enhancement. It provides the same template syntax and reactivity mental model as standard Vue. However, it is specifically optimized for "sprinkling" a small amount of interactions on an existing HTML page rendered by a server framework. See more details on how it differs from standard Vue.

  • Only ~6kb
  • Vue-compatible template syntax
  • DOM-based, mutates in place
  • Driven by @vue/reactivity

Status

  • This is pretty new. There are probably bugs and there might still be API changes, so use at your own risk. Is it usable though? Very much. Check out the examples to see what it's capable of.

  • The issue list is intentionally disabled because I have higher priority things to focus on for now and don't want to be distracted. If you found a bug, you'll have to either workaround it or submit a PR to fix it yourself. That said, feel free to use the discussions tab to help each other out.

  • Feature requests are unlikely to be accepted at this time - the scope of this project is intentionally kept to a bare minimum.

Usage

petite-vue can be used without a build step. Simply load it from a CDN:

<script src="https://unpkg.com/petite-vue" defer init></script>

<!-- anywhere on the page -->
<div v-scope="{ count: 0 }">
  {{ count }}
  <button @click="count++">inc</button>
</div>
  • Use v-scope to mark regions on the page that should be controlled by petite-vue.
  • The defer attribute makes the script execute after HTML content is parsed.
  • The init attribute tells petite-vue to automatically query and initialize all elements that have v-scope on the page.

Manual Init

If you don't want the auto init, remove the init attribute and move the scripts to end of <body>:

<script src="https://unpkg.com/petite-vue"></script>
<script>
  PetiteVue.createApp().mount()
</script>

Or, use the ES module build:

<script type="module">
  import { createApp } from 'https://unpkg.com/petite-vue?module'
  createApp().mount()
</script>

Production CDN URLs

The short CDN URL is meant for prototyping. For production usage, use a fully resolved CDN URL to avoid resolving and redirect cost:

  • Global build: https://unpkg.com/[email protected]/dist/petite-vue.iife.js
    • exposes PetiteVue global, supports auto init
  • ESM build: https://unpkg.com/[email protected]/dist/petite-vue.es.js
    • Must be used with <script type="module">

Root Scope

The createApp function accepts a data object that serves as the root scope for all expressions. This can be used to bootstrap simple, one-off apps:

<script type="module">
  import { createApp } from 'https://unpkg.com/petite-vue?module'

  createApp({
    // exposed to all expressions
    count: 0,
    // getters
    get plusOne() {
      return this.count + 1
    },
    // methods
    increment() {
      this.count++
    }
  }).mount()
</script>

<!-- v-scope value can be omitted -->
<div v-scope>
  <p>{{ count }}</p>
  <p>{{ plusOne }}</p>
  <button @click="increment">increment</button>
</div>

Note v-scope doesn't need to have a value here and simply serves as a hint for petite-vue to process the element.

Explicit Mount Target

You can specify a mount target (selector or element) to limit petite-vue to only that region of the page:

createApp().mount('#only-this-div')

This also means you can have multiple petite-vue apps to control different regions on the same page:

createApp({
  // root scope for app one
}).mount('#app1')

createApp({
  // root scope for app two
}).mount('#app2')

Lifecycle Events

You can listen to the special vue:mounted and vue:unmounted lifecycle events for each element (the vue: prefix is required since v0.4.0):

<div
  v-if="show"
  @vue:mounted="console.log('mounted on: ', $el)"
  @vue:unmounted="console.log('unmounted: ', $el)"
></div>

v-effect

Use v-effect to execute reactive inline statements:

<div v-scope="{ count: 0 }">
  <div v-effect="$el.textContent = count"></div>
  <button @click="count++">++</button>
</div>

The effect uses count which is a reactive data source, so it will re-run whenever count changes.

Another example of replacing the todo-focus directive found in the original Vue TodoMVC example:

<input v-effect="if (todo === editedTodo) $el.focus()" />

Components

The concept of "Components" are different in petite-vue, as it is much more bare-bones.

First, reusable scope logic can be created with functions:

<script type="module">
  import { createApp } from 'https://unpkg.com/petite-vue?module'

  function Counter(props) {
    return {
      count: props.initialCount,
      inc() {
        this.count++
      },
      mounted() {
        console.log(`I'm mounted!`)
      }
    }
  }

  createApp({
    Counter
  }).mount()
</script>

<div v-scope="Counter({ initialCount: 1 })" @vue:mounted="mounted">
  <p>{{ count }}</p>
  <button @click="inc">increment</button>
</div>

<div v-scope="Counter({ initialCount: 2 })">
  <p>{{ count }}</p>
  <button @click="inc">increment</button>
</div>

Components with Template

If you also want to reuse a piece of template, you can provide a special $template key on a scope object. The value can be the template string, or an ID selector to a <template> element:

<script type="module">
  import { createApp } from 'https://unpkg.com/petite-vue?module'

  function Counter(props) {
    return {
      $template: '#counter-template',
      count: props.initialCount,
      inc() {
        this.count++
      }
    }
  }

  createApp({
    Counter
  }).mount()
</script>

<template id="counter-template">
  My count is {{ count }}
  <button @click="inc">++</button>
</template>

<!-- reuse it -->
<div v-scope="Counter({ initialCount: 1 })"></div>
<div v-scope="Counter({ initialCount: 2 })"></div>

The <template> approach is recommended over inline strings because it is more efficient to clone from a native template element.

Global State Management

You can use the reactive method (re-exported from @vue/reactivity) to create global state singletons:

<script type="module">
  import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'

  const store = reactive({
    count: 0,
    inc() {
      this.count++
    }
  })

  // manipulate it here
  store.inc()

  createApp({
    // share it with app scopes
    store
  }).mount()
</script>

<div v-scope="{ localCount: 0 }">
  <p>Global {{ store.count }}</p>
  <button @click="store.inc">increment</button>

  <p>Local {{ localCount }}</p>
  <button @click="localCount++">increment</button>
</div>

Custom Directives

Custom directives are also supported but with a different interface:

const myDirective = (ctx) => {
  // the element the directive is on
  ctx.el
  // the raw value expression
  // e.g. v-my-dir="x" then this would be "x"
  ctx.exp
  // v-my-dir:foo -> "foo"
  ctx.arg
  // v-my-dir.mod -> { mod: true }
  ctx.modifiers
  // evaluate the expression and get its value
  ctx.get()
  // evaluate arbitrary expression in current scope
  ctx.get(`${ctx.exp} + 10`)

  // run reactive effect
  ctx.effect(() => {
    // this will re-run every time the get() value changes
    console.log(ctx.get())
  })

  return () => {
    // cleanup if the element is unmounted
  }
}

// register the directive
createApp().directive('my-dir', myDirective).mount()

This is how v-html is implemented:

const html = ({ el, get, effect }) => {
  effect(() => {
    el.innerHTML = get()
  })
}

Custom Delimiters (0.3+)

You can use custom delimiters by passing $delimiters to your root scope. This is useful when working alongside a server-side templating language that also uses mustaches:

createApp({
  $delimiters: ['${', '}']
}).mount()

Examples

Check out the examples directory.

Features

petite-vue only

  • v-scope
  • v-effect
  • @vue:mounted & @vue:unmounted events

Has Different Behavior

  • In expressions, $el points to the current element the directive is bound to (instead of component root element)
  • createApp() accepts global state instead of a component
  • Components are simplified into object-returning functions
  • Custom directives have a different interface

Vue Compatible

  • {{ }} text bindings (configurable with custom delimiters)
  • v-bind (including : shorthand and class/style special handling)
  • v-on (including @ shorthand and all modifiers)
  • v-model (all input types + non-string :value bindings)
  • v-if / v-else / v-else-if
  • v-for
  • v-show
  • v-html
  • v-text
  • v-pre
  • v-once
  • v-cloak
  • reactive()
  • nextTick()
  • Template refs

Not Supported

Some features are dropped because they have a relatively low utility/size ratio in the context of progressive enhancement. If you need these features, you should probably just use standard Vue.

  • ref(), computed() etc.
  • Render functions (petite-vue has no virtual DOM)
  • Reactivity for Collection Types (Map, Set, etc., removed for smaller size)
  • Transition, KeepAlive, Teleport, Suspense
  • v-for deep destructure
  • v-on="object"
  • v-is & <component :is="xxx">
  • v-bind:style auto-prefixing

Comparison with standard Vue

The point of petite-vue is not just about being small. It's about using the optimal implementation for the intended use case (progressive enhancement).

Standard Vue can be used with or without a build step. When using a build setup (e.g. with Single-File Components), we pre-compile all the templates so there's no template processing to be done at runtime. And thanks to tree-shaking, we can ship optional features in standard Vue that doesn't bloat your bundle size when not used. This is the optimal usage of standard Vue, but since it involves a build setup, it is better suited when building SPAs or apps with relatively heavy interactions.

When using standard Vue without a build step and mounting to in-DOM templates, it is much less optimal because:

  • We have to ship the Vue template compiler to the browser (13kb extra size)
  • The compiler will have to retrieve the template string from already instantiated DOM
  • The compiler then compiles the string into a JavaScript render function
  • Vue then replaces existing DOM templates with new DOM generated from the render function.

petite-vue avoids all this overhead by walking the existing DOM and attaching fine-grained reactive effects to the elements directly. The DOM is the template. This means petite-vue is much more efficient in progressive enhancement scenarios.

This is also how Vue 1 worked. The trade-off here is that this approach is coupled to the DOM and thus not suitable for platform agnostic rendering or JavaScript SSR. We also lose the ability to work with render functions for advanced abstractions. However as you can probably tell, these capabilities are rarely needed in the context of progressive enhancement.

Comparison with Alpine

petite-vue is indeed addressing a similar scope to Alpine, but aims to be (1) even more minimal and (2) more Vue-compatible.

  • petite-vue is around half the size of Alpine.

  • petite-vue has no transition system (maybe this can be an opt-in plugin).

  • Although Alpine largely resembles Vue's design, there are various cases where the behavior is different from Vue itself. It may also diverge more from Vue in the future. This is good because Alpine shouldn't have to restrict its design to strictly follow Vue - it should have the freedom to develop in a direction that makes sense for its goals.

    In comparison, petite-vue will try to align with standard Vue behavior whenever possible so that there is less friction moving to standard Vue if needed. It's intended to be part of the Vue ecosystem to cover the progressive enhancement use case where standard Vue is less optimized for nowadays.

Security and CSP

petite-vue evaluates JavaScript expressions in the templates. This means if petite-vue is mounted on a region of the DOM that contains non-sanitized HTML from user data, it may lead to XSS attacks. If your page renders user-submitted HTML, you should prefer initializing petite-vue using explicit mount target so that it only processes parts that are controlled by you. You can also sanitize any user-submitted HTML for the v-scope attribute.

petite-vue evaluates the expressions using new Function(), which may be prohibited in strict CSP settings. There is no plan to provide a CSP build because it involves shipping an expression parser which defeats the purpose of being lightweight. If you have strict CSP requirements, you should probably use standard Vue and pre-compile the templates.

License

MIT

More Repositories

1

vue

This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
TypeScript
206,615
star
2

awesome-vue

🎉 A curated list of awesome things related to Vue.js
70,860
star
3

core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript
43,920
star
4

vue-cli

🛠️ webpack-based tooling for Vue.js Development
JavaScript
29,747
star
5

vuex

🗃️ Centralized State Management for Vue.js.
JavaScript
28,336
star
6

devtools

⚙️ Browser devtools extension for debugging Vue.js applications.
TypeScript
24,243
star
7

vuepress

📝 Minimalistic Vue-powered static site generator
JavaScript
22,293
star
8

vue-router

🚦 The official router for Vue 2
JavaScript
19,008
star
9

pinia

🍍 Intuitive, type safe, light and flexible Store for Vue using the composition api with DevTools support
TypeScript
12,284
star
10

vitepress

Vite & Vue powered static site generator.
TypeScript
10,982
star
11

vue-hackernews-2.0

HackerNews clone built with Vue 2.0, vue-router & vuex, with server-side rendering
JavaScript
10,964
star
12

apollo

🚀 Apollo/GraphQL integration for VueJS
TypeScript
5,980
star
13

vue-class-component

ES / TypeScript decorator for class-style Vue components.
TypeScript
5,812
star
14

vetur

Vue tooling for VS Code.
TypeScript
5,721
star
15

language-tools

⚡ High-performance Vue language tooling based-on Volar.js
TypeScript
5,403
star
16

v2.vuejs.org

📄 Documentation for Vue 2
JavaScript
5,051
star
17

vue-loader

📦 Webpack loader for Vue.js components
TypeScript
4,970
star
18

rfcs

RFCs for substantial changes / feature additions to Vue core
4,822
star
19

eslint-plugin-vue

Official ESLint plugin for Vue.js
JavaScript
4,365
star
20

composition-api

Composition API plugin for Vue 2
TypeScript
4,176
star
21

vuefire

🔥 Firebase bindings for Vue.js
TypeScript
3,784
star
22

router

🚦 The official router for Vue.js
TypeScript
3,588
star
23

vue-test-utils

Component Test Utils for Vue 2
JavaScript
3,569
star
24

vue-rx

👁️ RxJS integration for Vue.js.
JavaScript
3,343
star
25

create-vue

🛠️ The recommended way to start a Vite-powered Vue project
Vue
3,297
star
26

docs

📄 Documentation for Vue 3
Vue
2,788
star
27

vue-touch

Hammer.js wrapper for Vue.js
JavaScript
2,728
star
28

vuex-router-sync

Effortlessly keep vue-router and vuex store in sync.
JavaScript
2,523
star
29

vue-hackernews

HackerNews clone with Vue.js
Vue
2,514
star
30

v2.cn.vuejs.org

🇨🇳 Chinese translation for v2.vuejs.org
JavaScript
1,865
star
31

babel-plugin-transform-vue-jsx

babel plugin for vue 2.0 jsx
JavaScript
1,844
star
32

babel-plugin-jsx

JSX for Vue 3
TypeScript
1,668
star
33

vue-syntax-highlight

💡 Sublime Text syntax highlighting for single-file Vue components
1,481
star
34

jsx-vue2

monorepo for Babel / Vue JSX related packages
JavaScript
1,450
star
35

ui

💻 UI components for official Vue organization apps
Vue
1,331
star
36

vue-docs-zh-cn

该项目已不再维护,有劳通过 Vue 官网查阅最新的文档
1,330
star
37

core-vapor

Vue Vapor is a variant of Vue that offers rendering without the Virtual DOM.
TypeScript
1,205
star
38

vueify

Browserify transform for single-file Vue components
JavaScript
1,172
star
39

vue-web-component-wrapper

(Vue 2 only) Wrap a Vue component as a web component / custom element.
JavaScript
1,036
star
40

docs-next-zh-cn

🇨🇳 Chinese translation for v3.vuejs.org
Vue
959
star
41

test-utils

Vue Test Utils for Vue 3
TypeScript
957
star
42

devtools-next

The next iteration of Vue DevTools
TypeScript
882
star
43

roadmap

🗺️ Roadmap for the Vue.js project (archive)
851
star
44

rollup-plugin-vue

Roll .vue files
TypeScript
846
star
45

repl

Vue SFC REPL as a Vue 3 component
TypeScript
799
star
46

vue-jest

Jest Vue transformer
JavaScript
741
star
47

vue-migration-helper

CLI tool to aid in migration from Vue 1.x to 2.0
JavaScript
595
star
48

vue-dev-server

A POC dev server that allows you to import `*.vue` files via native ES modules imports.
TypeScript
572
star
49

vue2-ssr-docs

Vue.js Server-Side Rendering Guide (for Vue 2)
559
star
50

vue-hot-reload-api

🌶️ Hot reload API for Vue components
JavaScript
465
star
51

vue-animated-list

A Vue.js plugin for easily animating `v-for` rendered lists.
JavaScript
462
star
52

vue-next-webpack-preview

JavaScript
427
star
53

vue-eslint-parser

The ESLint custom parser for `.vue` files.
TypeScript
422
star
54

vue-async-data

Async data loading plugin
JavaScript
417
star
55

vue-component-compiler

Compile a single file Vue component into a CommonJS module.
TypeScript
341
star
56

vue-cli-plugin-vue-next

A Vue CLI plugin for trying out vue-next (experimental)
JavaScript
339
star
57

eslint-config-vue

JavaScript
326
star
58

component-compiler-utils

Lower level utilities for compiling Vue single file components
TypeScript
318
star
59

blog

📝 The official Vue.js blog
Vue
296
star
60

vue-test-utils-jest-example

Example project using Jest + vue-test-utils together
JavaScript
296
star
61

tsconfig

Base tsconfig for Vue 3 projects.
280
star
62

vue-template-explorer

Vue template compilation explorer
Vue
263
star
63

events

Source code for the new Vue.js Events page
Vue
252
star
64

vue-codemod

Vue.js codemod scripts
TypeScript
250
star
65

jp.vuejs.org

🇯🇵 Japanese translation for vuejs.org
JavaScript
246
star
66

theme

VitePress theme for vuejs.org.
Vue
217
star
67

v3-migration-guide

Vue 2 -> Vue 3 migration guide
JavaScript
211
star
68

vue-element

register a custom element with Vue.js.
JavaScript
208
star
69

vue-curated

🖼️ The curated Vue packages list
177
star
70

Discussion

Vue.js discussion
166
star
71

vuex-observable

Consume Vuex actions as Observables using RxJS 5
JavaScript
155
star
72

vue-issue-helper

Vue
145
star
73

composition-api-converter

Automatically migrate components to the Function API
JavaScript
145
star
74

babel-preset-vue-app

Babel preset for Vue app.
JavaScript
125
star
75

art

🎨 Artworks
121
star
76

laravel-elixir-vue-2

Laravel Elixir Vue 2.0 support plugin
JavaScript
106
star
77

composition-api-rfc

Vuepress render for the Composition API RFC
JavaScript
106
star
78

vue-router-demos

Live demos for vue-router
Vue
106
star
79

eslint-plugin-vue-libs

Eslint plugin for Vue internal development
JavaScript
105
star
80

vue-test-utils-mocha-webpack-example

Example project using mocha-webpack and vue-test-utils
JavaScript
104
star
81

eslint-config-typescript

eslint-config-typescript for vue projects
JavaScript
103
star
82

babel-preset-vue

Babel preset for transforming Vue JSX.
JavaScript
87
star
83

ecosystem-ci

Vue Ecosystem CI
TypeScript
81
star
84

vue-test-utils-getting-started

Demo project for `vue-test-utils`
JavaScript
81
star
85

vue-webpack-meteor-example

Example using Vue with Meteor, while leveraging the normal Webpack + NPM workflow for your front-end.
Vue
78
star
86

vue-requests

Need a Vue.js module or looking for ideas?
70
star
87

eslint-config-airbnb

ESLint Shareable Configs for Airbnb JavaScript Style Guide in Vue.js Projects
JavaScript
67
star
88

news.vuejs.org

Vue.js News Portal
Vue
66
star
89

vue-curated-client

Official curation list client
Vue
65
star
90

eslint-config-prettier

eslint-config-prettier for vue-cli
JavaScript
61
star
91

vue-template-es2015-compiler

Support a subset of handy ES2015 features in Vue 2.0 templates.
JavaScript
60
star
92

vue-test-utils-typescript-example

Example project using TypeScript, Jest + vue-test-utils together
Vue
59
star
93

create-eslint-config

Utility to setup ESLint in Vue.js projects.
JavaScript
41
star
94

vue-ssr-html-stream

Transform stream to simplify Vue SSR streaming
HTML
40
star
95

eslint-config-standard

ESLint Shareable Configs for JavaScript Standard Style in Vue.js Projects
JavaScript
39
star
96

create-vue-templates

Snapshots of the generated templates of `npm create vue@latest`
Vue
39
star
97

it.vuejs.org

Italian translation for vuejs.org 🇮🇹
JavaScript
35
star
98

systemjs-plugin-vue

SystemJS plugin for Vue single file components
JavaScript
34
star
99

test-utils-docs

Docs for vue-test-utils-next
JavaScript
32
star
100

vue-curated-server

JavaScript
31
star