Skip to main content

Collect Vue single-file components into a single HTML file for browser use

Project description

vue-collector

A pure-Python tool for compiling Vue single-file components (.vue files) into browser-ready assets — no Node.js, no npm, no build toolchain required.

Purpose

vue-collector is a prototyping tool, not a production bundler. It lets you write Vue components using plain .vue files and compile them from Python, without setting up a JavaScript build pipeline.

Language support is intentionally minimal: plain JavaScript only, LESS for styles. TypeScript, <script setup>, CSS Modules, and other preprocessors are not supported and will raise errors. This is a deliberate trade-off to keep the tool dependency-free from the Node.js ecosystem.

What it is:

  • A quick way to add Vue components to a Python backend (Flask, FastAPI, Django, etc.)
  • Suitable for internal tools, dashboards, and prototypes where plain JS is enough

What it is not:

  • A replacement for Vite, Webpack, or Rollup
  • Production-ready: no tree-shaking, no code splitting, no hot-reload, no module resolution

When to use it:

  • You want a few interactive Vue pieces in a Python app without touching npm
  • Simplicity and zero JS tooling beats optimal bundle size
  • You plan to migrate to a proper Vite project later

Component format constraints

Components must follow a simplified subset of the Vue SFC format:

  • export default { ... } is the only supported way to define a component — no defineComponent(), no <script setup>, no other registration patterns
  • No import statements in <script> — browser globals only (Vue, your app globals)
  • No @import in <style> — inline styles only
  • One <template>, <script>, and <style> section per file
  • LESS is the only supported style language — <style> and <style lang="less"> are accepted; any other lang value (e.g. scss, stylus) raises an error
  • No TypeScript<script lang="ts"> raises an error; plain JavaScript only
  • <style scoped> is supported — adds [data-v-*] attribute scoping automatically
<!-- components/Counter.vue -->
<template>
  <div class="counter">
    <span>{{ count }}</span>
    <button @click="increment">+</button>
  </div>
</template>

<script>
export default {
  name: 'Counter',
  data() {
    return { count: 0 }
  },
  methods: {
    increment() { this.count++ }
  }
}
</script>

<style scoped>
.counter { display: flex; gap: 8px; }
button { cursor: pointer; }
</style>

Build mode 1 — HTML file

All components are injected into a single index.html produced from your template.html.

template.html:

<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <style><|style|></style>
</head>
<body>
  <div id="app">
    <counter />
  </div>

  <|templates|>

  <script>
    <|variables|>
    const app = Vue.createApp({});
    <|components|>
    app.mount('#app');
  </script>
</body>
</html>

Templates are stored as <template id="..."> tags and referenced by selector from app.component().

Python:

from vue_collector import prepare_compiled

with open('template.html') as f:
    html = prepare_compiled(f.read(), vue_dir='vue/')

with open('index.html', 'w') as f:
    f.write(html)

Project layout for this mode:

project/
├── template.html       # your HTML skeleton with <|placeholders|>
├── index.html          # generated output
└── vue/
    ├── Counter.vue
    └── Card.vue

Build mode 2 — Standalone JS + CSS assets

Components are compiled into two files named by a content hash, so filenames change automatically whenever any .vue file changes (safe for long-term browser caching).

Templates are inlined as backtick strings inside app.component() — no <template id> tags needed. The JS file exports a single initComponents(app) function.

Python:

from vue_collector import write_assets

js_file, css_file = write_assets(
    vue_dir='vue/',      # directory containing .vue files
    output_dir='static', # writes files here
    extra_js='',         # optional JS prepended verbatim (e.g. app init code)
)
# js_file  → 'components.a3f9c1d2e4b5f678.js'
# css_file → 'components.a3f9c1d2e4b5f678.css'

Or in-memory:

from vue_collector import prepare_assets

js_content, css_content = prepare_assets(vue_dir='vue/')

Generated JS structure:

// extra_js content goes here (if provided)

// module-level constants (code outside export default in .vue scripts)
const PAGE_SIZE = 10

function initComponents(app) {
    app.component('Counter', {template: `
  <div class="counter">
    <span>{{ count }}</span>
    <button @click="increment">+</button>
  </div>
`,
name: 'Counter',
data() { return { count: 0 } },
methods: { increment() { this.count++ } }});
}

HTML page using generated assets:

<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <link rel="stylesheet" href="/static/components.a3f9c1d2e4b5f678.css">
</head>
<body>
  <div id="app">
    <counter />
  </div>
  <script src="/static/components.a3f9c1d2e4b5f678.js"></script>
  <script>
    const app = Vue.createApp({});
    initComponents(app);
    app.mount('#app');
  </script>
</body>
</html>

Project layout for this mode:

project/
├── static/
│   ├── components.a3f9c1d2e4b5f678.js    # generated
│   └── components.a3f9c1d2e4b5f678.css   # generated
└── vue/
    ├── Counter.vue
    └── Card.vue

Flask integration example

from flask import Flask, render_template_string
from vue_collector import write_assets, VueSectionError

app = Flask(__name__)

try:
    js_file, css_file = write_assets(vue_dir='vue/', output_dir='static')
except VueSectionError as e:
    print(f'Component error: {e}')
    raise

PAGE = """
<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <link rel="stylesheet" href="/static/{{ css }}">
</head>
<body>
  <div id="app"><my-counter /></div>
  <script src="/static/{{ js }}"></script>
  <script>
    const app = Vue.createApp({});
    initComponents(app);
    app.mount('#app');
  </script>
</body>
</html>
"""

@app.route('/')
def index():
    return render_template_string(PAGE, js=js_file, css=css_file)

Auto-reload with watchdog

find_vue_files is useful for watching .vue files with a file watcher:

from vue_collector import find_vue_files, write_assets

# Get all .vue paths to pass to your watchdog observer
paths_to_watch = find_vue_files('vue/')

Low-level API

from vue_collector import VueComponent, collect_vue, VueSectionError

# Parse a single component
with open('vue/Counter.vue') as f:
    vc = VueComponent('Counter.vue', f.read())

print(vc.name)          # 'Counter'
print(vc.style)         # '.counter{display:flex;gap:8px;}'
print(vc.raw_template)  # '<div class="counter">...</div>'  (for JS inline use)
print(vc.template)      # '<template id="template-counter">...</template>'  (for HTML mode)

# Iterate all components in a directory — yields VueComponent objects
for component in collect_vue('vue/'):
    print(component.name, component.style)

# Errors always come as VueSectionError
try:
    VueComponent('Bad.vue', '<template><div></template>')
except VueSectionError as e:
    print(e.file_name)  # 'Bad.vue'
    print(e.section)    # None (structural error), or 'script' / 'style'
    print(e.message)    # human-readable description

Installation

pip install vue-collector

Limitations

Feature Supported
LESS compilation Yes — only supported style language; CSS compiles fine without an explicit lang attribute
<style scoped> Yes
Vue directives (v-for, v-if, @click, :bind) Pass-through (not validated)
export default {} as component definition Yes (only supported form)
defineComponent() / <script setup> No
import in <script> No
@import in <style> No
TypeScript No
Multiple root elements (Vue 3 fragments) No (parser expects one root)
CSS Modules No

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vue_collector-0.1.0.tar.gz (25.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vue_collector-0.1.0-py3-none-any.whl (13.1 kB view details)

Uploaded Python 3

File details

Details for the file vue_collector-0.1.0.tar.gz.

File metadata

  • Download URL: vue_collector-0.1.0.tar.gz
  • Upload date:
  • Size: 25.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Linux Mint","version":"22.2","id":"zara","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for vue_collector-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1c6c9a20b2e75ec4f5f29d0ebe7acf9568073529a63dd7ac41933aa41f0836f1
MD5 5903a5c192e66cc1fe23ae91f8193d3d
BLAKE2b-256 95d4588600ef69a6a162d4a6cb5a74942e8d1b20aabf04ea41026a3c6eb6f0e8

See more details on using hashes here.

File details

Details for the file vue_collector-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: vue_collector-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Linux Mint","version":"22.2","id":"zara","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for vue_collector-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 48aed667aa3bec6d67a75c5330d199508a67f61ef7c1e8cbc249791af1379bbd
MD5 25854179dfd5a54782d7fb68861240c4
BLAKE2b-256 1783b80378a58ffebf86abd6e6ff0f7748f93372bd5f4abec05b38d7a05590ee

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page