mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-08 19:06:15 -08:00
feat(vue): [EX-02] verify installed consumers and preserve lifecycle contracts
This commit is contained in:
1 parent
4df9689364
commit
d62ab13a35
29 files changed
+2326
-82
No files matched your search
+68
-21
@@ -1,29 +1,76 @@
|
||||
# vue-project
|
||||
# Vue consumer example
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
|
||||
|
||||
## Customize configuration
|
||||
|
||||
See [Vite Configuration Reference](https://vite.dev/config/).
|
||||
|
||||
## Project Setup
|
||||
Run the example from the repository root with Node from .node-version and Yarn
|
||||
Classic 1.22.22. Use yarn install --frozen-lockfile and only the root yarn.lock.
|
||||
|
||||
```sh
|
||||
npm install
|
||||
yarn dev:vue
|
||||
yarn typecheck:vue
|
||||
yarn lint:vue
|
||||
yarn build:vue
|
||||
yarn test:vue-consumer
|
||||
```
|
||||
|
||||
### Compile and Hot-Reload for Development
|
||||
The build output is refactor/.cache/vue-example-dist.
|
||||
Rebuild changed library distributions with yarn build followed by the package name.
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
## Files and ownership
|
||||
|
||||
### Compile and Minify for Production
|
||||
- src/Player.vue owns the player and container through shallow refs. It constructs
|
||||
once on mount, emits getInstance, then releases its reference before calling
|
||||
destroy(false) on owner unmount. Vue owns the outer div. Player state is private:
|
||||
the component ref exposes the normal Vue surface, not an art property.
|
||||
- src/player-options.ts holds this example's existing configuration overrides:
|
||||
French language, French/Indonesian dictionaries and fresh Danmuku/Document PiP
|
||||
factories per mount. They still override option.lang, i18n and plugins. The
|
||||
container comes from Vue; other options pass through. The url assertion preserves
|
||||
the historical Partial input while the core performs runtime validation.
|
||||
- src/App.vue demonstrates the existing event/prop syntax. Its reactive option
|
||||
object keeps narrow field inference and is checked against `Partial<Option>`.
|
||||
- src/main.ts is the client entry referenced by index.html. tsconfig.json replaces
|
||||
jsconfig.json, preserves the @ alias and enables strict source/template checking.
|
||||
- vite.config.js uses the standard Vue plugin. The unused optional devtools overlay
|
||||
was removed from this example's build dependencies; no player UI was changed.
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
## Compatibility and updates
|
||||
|
||||
The wrapper retains required option: `Partial<Option>` and the getInstance event.
|
||||
The array-form event declaration remains intentionally unchanged: historical
|
||||
listener type extraction is not narrowed. Annotate event handlers with Artplayer
|
||||
as App.vue does. Missing URLs may typecheck through Partial but still fail the
|
||||
core's runtime validation.
|
||||
|
||||
Changing an option object or its fields does not recreate or update the player.
|
||||
Use the received instance's methods, such as switchUrl, for live updates. Change
|
||||
the component key to reconstruct using the latest options. No deep option watcher
|
||||
or new event/ref contract was introduced. CSS classes and styles still fall through
|
||||
to the root div; other native attributes continue to work for JS consumers.
|
||||
Strict template checking distinguishes declared props from arbitrary attributes.
|
||||
|
||||
Vue captures listener errors through its error handling. A mounted component
|
||||
retains its instance after a captured listener error and destroys it on unmount.
|
||||
KeepAlive deactivation retains the instance; owner unmount destroys it. The example
|
||||
does not silently pause or destroy players when cached. Use player APIs if your
|
||||
application needs that behavior.
|
||||
|
||||
## Reproducible checks
|
||||
|
||||
Root development dependencies pin Vue/compiler-sfc 3.5.28, Vue Vite plugin 6.0.1,
|
||||
vue-tsc 3.3.11, TypeScript 5.9.3 and Vite 7.3.6. No player runtime dependency changes.
|
||||
The isolated consumer installs actual packed core, Danmuku and Document PiP files,
|
||||
frozen-reinstalls them, and verifies every package file. Its Vue compiler and all
|
||||
resolved declarations also live in that isolated install; no source aliases or
|
||||
workspace type fallbacks are permitted. A plain-JS SFC separately verifies the
|
||||
legacy event, attribute and repeated-mount syntax.
|
||||
|
||||
Development/production browser runs cover native play/pause/seek and pixels,
|
||||
instance API source updates, option/key behavior, refs, siblings, repeated mount,
|
||||
listener errors, KeepAlive and real Worker termination. Video/XML responses use
|
||||
controlled fixtures. Plugin registration does not certify window PiP interaction,
|
||||
full Danmuku scheduling, CDN availability or physical macOS/iOS Safari.
|
||||
|
||||
yarn test:vue-consumer --before runs the original Player.vue from the recorded Git
|
||||
baseline against the same candidate packages. Both old and new wrappers must pass;
|
||||
this is a compatibility control, not an old published npm wrapper test. Evidence
|
||||
is retained in unique refactor/.cache/vue-consumer-* folders. GitHub runs the test
|
||||
and uploads these reports; local success does not imply verified remote jobs.
|
||||
@@ -0,0 +1,2 @@
|
||||
// Reuse the shared Vue and TypeScript rules.
|
||||
export { default } from '../../eslint.config.js'
|
||||
@@ -1,13 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>artplayer-vue</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
@@ -3,23 +3,28 @@
|
||||
"type": "module",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"packageManager": "yarn@1.22.22",
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
"build": "yarn typecheck && vite build",
|
||||
"preview": "vite preview",
|
||||
"typecheck": "vue-tsc -p tsconfig.json --noEmit",
|
||||
"lint": "eslint ."
|
||||
},
|
||||
"dependencies": {
|
||||
"artplayer": "^5.3.0-beta.4",
|
||||
"artplayer-plugin-danmuku": "^5.2.0",
|
||||
"artplayer-plugin-document-pip": "^1.0.2",
|
||||
"vue": "^3.5.21"
|
||||
"vue": "3.5.28"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"vite": "^7.1.4",
|
||||
"vite-plugin-vue-devtools": "^8.0.1"
|
||||
"@vitejs/plugin-vue": "6.0.1",
|
||||
"eslint": "9.39.2",
|
||||
"typescript": "5.9.3",
|
||||
"vite": "7.3.6",
|
||||
"vue-tsc": "3.3.11"
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import type Artplayer from 'artplayer'
|
||||
import type { Option } from 'artplayer'
|
||||
import { reactive } from 'vue'
|
||||
import Artplayer, { type Option } from 'artplayer'
|
||||
import Player from './Player.vue'
|
||||
|
||||
const option = reactive<Partial<Option>>({
|
||||
const option = reactive({
|
||||
url: 'https://artplayer.org/assets/sample/video.mp4',
|
||||
autoSize: true,
|
||||
})
|
||||
} satisfies Partial<Option>)
|
||||
|
||||
const style = reactive({
|
||||
width: '800px',
|
||||
@@ -15,6 +16,7 @@ const style = reactive({
|
||||
})
|
||||
|
||||
function getInstance(art: Artplayer) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Artplayer instance:', art)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,44 +1,28 @@
|
||||
<script setup lang="ts">
|
||||
import { onBeforeUnmount, onMounted, ref, shallowRef } from 'vue'
|
||||
import type { Option } from 'artplayer'
|
||||
import Artplayer from 'artplayer'
|
||||
|
||||
// Test type
|
||||
import Artplayer, { type Option } from 'artplayer'
|
||||
|
||||
// Test i18n
|
||||
import fr from 'artplayer/i18n/fr'
|
||||
import id from 'artplayer/i18n/id'
|
||||
|
||||
// Test plugins
|
||||
import artplayerPluginDocumentPip from 'artplayer-plugin-document-pip'
|
||||
import artplayerPluginDanmuku from 'artplayer-plugin-danmuku'
|
||||
import { onBeforeUnmount, onMounted, shallowRef } from 'vue'
|
||||
import { playerOptions } from './player-options'
|
||||
|
||||
const props = defineProps<{ option: Partial<Option> }>()
|
||||
const emit = defineEmits(['getInstance'])
|
||||
|
||||
const art = shallowRef<Artplayer | null>(null)
|
||||
const $container = ref<HTMLDivElement | null>(null)
|
||||
const $container = shallowRef<HTMLDivElement | null>(null)
|
||||
|
||||
onMounted(() => {
|
||||
art.value = new Artplayer({
|
||||
...props.option,
|
||||
url: props.option.url as string,
|
||||
container: $container.value as HTMLDivElement,
|
||||
i18n: { id, fr },
|
||||
lang: 'fr',
|
||||
plugins: [
|
||||
artplayerPluginDocumentPip({
|
||||
//
|
||||
}),
|
||||
artplayerPluginDanmuku({
|
||||
danmuku: 'https://artplayer.org/assets/sample/danmuku.xml',
|
||||
}),
|
||||
],
|
||||
})
|
||||
const container = $container.value
|
||||
if (!container)
|
||||
return
|
||||
art.value = new Artplayer(playerOptions(props.option, container))
|
||||
emit('getInstance', art.value)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
art.value?.destroy(false)
|
||||
const instance = art.value
|
||||
art.value = null
|
||||
instance?.destroy(false)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
File renamed without changes.
@@ -0,0 +1,23 @@
|
||||
import type { Option } from 'artplayer'
|
||||
import artplayerPluginDanmuku from 'artplayer-plugin-danmuku'
|
||||
import artplayerPluginDocumentPip from 'artplayer-plugin-document-pip'
|
||||
import fr from 'artplayer/i18n/fr'
|
||||
import id from 'artplayer/i18n/id'
|
||||
|
||||
// Preserve this example's existing overrides and create plugins per instance.
|
||||
export function playerOptions(option: Partial<Option>, container: HTMLDivElement): Option {
|
||||
return {
|
||||
...option,
|
||||
container,
|
||||
// Partial<Option> is the historical wrapper API; Artplayer validates missing URLs.
|
||||
url: option.url as string,
|
||||
i18n: { id, fr },
|
||||
lang: 'fr',
|
||||
plugins: [
|
||||
artplayerPluginDocumentPip({}),
|
||||
artplayerPluginDanmuku({
|
||||
danmuku: 'https://artplayer.org/assets/sample/danmuku.xml',
|
||||
}),
|
||||
],
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"paths": { "@/*": ["./src/*"] },
|
||||
"types": [],
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": false
|
||||
},
|
||||
"vueCompilerOptions": { "strictTemplates": true },
|
||||
"include": ["src"]
|
||||
}
|
||||
@@ -2,13 +2,11 @@ import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import { defineConfig } from 'vite'
|
||||
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
vueDevTools(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
|
||||
Reference in new issue
Block a user