Skip to content

Bundle size and import paths ​

Choose the smallest entry that supplies the components you use. Every component registers its own upstream elements. The existing videojs-vue, videojs-vue/audio, and videojs-vue/ui aggregate entries remain available, including their registration side effects.

Use caseImport pathExports
Video without a skinvideojs-vue/corePlayerRoot, Video, video types
Video state and commandsvideojs-vue/composablesusePlayerState, usePlayerActions, handle/state/action types
Audio without a skinvideojs-vue/audio/coreAudioPlayerRoot, Audio, audio types
Audio state and commandsvideojs-vue/audio/composablesuseAudioPlayerState, useAudioPlayerActions, handle/state/action types
Default video playervideojs-vue/video/defaultVideoPlayer, video types, VideoMediaComponent
Neutral video playervideojs-vue/video/neutralVideoPlayer, video types, VideoMediaComponent
Compat video playervideojs-vue/video/compatVideoPlayer, video types, VideoMediaComponent
Compat video skinvideojs-vue/skins/compatCompatVideoSkin
Default audio playervideojs-vue/audio/defaultAudioPlayer, audio types, AudioMediaComponent
Neutral audio playervideojs-vue/audio/neutralAudioPlayer, audio types, AudioMediaComponent
One video skinvideojs-vue/skins/default or videojs-vue/skins/neutralDefaultVideoSkin or NeutralVideoSkin
One audio skinvideojs-vue/audio/skins/default or videojs-vue/audio/skins/neutralDefaultAudioSkin or NeutralAudioSkin
One controlvideojs-vue/ui/play-button, etc.The corresponding UI component

The fixed player entries share the aggregate players' media props, events, exposed handles, slots, and lifecycle. Their optional skin prop accepts only the skin bound by that entry; omit it in normal use. To switch between default and neutral skins at runtime, use VideoPlayer from videojs-vue or AudioPlayer from videojs-vue/audio. These aggregate players load those two skins. Compat is available through its dedicated entries; see Compat skin for usage and browser requirements.

vue
<script setup lang="ts">
import { shallowRef } from 'vue'
import { VideoPlayer } from 'videojs-vue/video/default'
import type { PlayerHandle } from 'videojs-vue/core'
import { usePlayerState } from 'videojs-vue/composables'

const player = shallowRef<PlayerHandle | null>(null)
const paused = usePlayerState(state => state.paused, player)
</script>

<template>
  <VideoPlayer
    ref="player"
    src="/demo.mp4"
  />
  <p>Paused: {{ paused }}</p>
</template>

All entries share the same internal injection keys. Composables imported from their lightweight entry work under a root or complete player imported from any compatible video or audio entry.

Optional downloads ​

HLS remains separate at videojs-vue/media/hls. A static import includes its engine in the initial dependency graph. Use defineAsyncComponent(() => import('videojs-vue/media/hls').then(module => module.HlsVideo)) when it should load only when rendered; install the optional adapter dependency first.

Video skins and i18n can emit lazy locale chunks. Emitted files are not all initial downloads: the active locale determines which language pack loads at runtime. The size report separates initial static imports from asynchronous chunks.

Reproduce measurements ​

From the repository root:

sh
pnpm build
pnpm size
pnpm size:check
pnpm test:package
pnpm play:build
pnpm size:play

size bundles production consumers of the actual package exports in dist, includes upstream dependencies, externalizes Vue, and reports gzip bytes for the initial graph, asynchronous chunks, and their total. Full module and chunk graphs are written to .cache/bundle-size/report.json. It does not override dependency side-effect metadata.

benchmarks/baseline.json records the pre-optimization consumer measurements. benchmarks/budgets.json fixes per-scenario budgets with approximately 5% headroom. size:check also checks required registrations and rejects unwanted skins, audio/video dependencies, or HLS in lightweight entries. Budget changes need a measured explanation; they are not updated automatically.

The Compat entry measured 77,616 initial gzip bytes and 61,889 asynchronous gzip bytes (139,505 total) with @videojs/html@10.0.1, excluding Vue. Its new budget allows approximately 5% headroom. The dependency graph check requires Compat registration and excludes default/neutral skins; existing entry checks also reject accidental Compat imports.

test:package checks isolated entry registration, cross-entry injection, media binding, events, slots, KeepAlive, cleanup, and SSR. size:play follows the Vite manifest's static imports for the default page and confirms that audio, custom controls, and HLS remain asynchronous. Unlike library measurements, the playground report includes Vue and the demo UI.