Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .nx/version-plans/version-plan-1787025000000.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
core-bundle: patch
---

fix(vue): 解除响应式歌词数据的 Vue Proxy,避免 Core 克隆失败
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"scripts": {
"build:libs": "nx run-many --target=build --projects=tag:library",
"ci:build:libs": "pnpm run build:libs",
"test:libs": "nx run-many --target=test --projects=core,ttml,lyric",
"test:libs": "nx run-many --target=test --projects=core,ttml,lyric,vue",
"ci:test:libs": "pnpm run test:libs",
"format": "biome format . --write",
"lint": "biome lint . --fix",
Expand Down
4 changes: 2 additions & 2 deletions packages/playground/vue/src/TestApp.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import {
LyricPlayer,
type LyricPlayerRef,
} from "@applemusic-like-lyrics/vue";
import { onMounted, reactive, ref, shallowRef } from "vue";
import { onMounted, reactive, ref } from "vue";

const audioRef = ref<HTMLAudioElement>();
const state = reactive({
Expand All @@ -54,7 +54,7 @@ const state = reactive({
albumIsVideo: false,
currentTime: 0,
});
const lyricLines = shallowRef<LyricLine[]>([]);
const lyricLines = ref<LyricLine[]>([]);

const playerRef = ref<LyricPlayerRef>();
const bgRef = ref<BackgroundRenderRef>();
Expand Down
12 changes: 9 additions & 3 deletions packages/vue/README-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,18 @@ yarn add @applemusic-like-lyrics/vue # 使用 yarn
一个测试用途的程序可以在 [../playground/vue/src/test.ts](../playground/vue/src/test.ts) 里找到。

```vue
<tamplate>
<LyricPlayer :lyric-lines="[]" :current-time="0" />
</tamplate>
<template>
<LyricPlayer :lyric-lines="lyricLines" :current-time="0" />
</template>

<script setup lang="ts">
import type { LyricLine } from "@applemusic-like-lyrics/core";
import { LyricPlayer } from "@applemusic-like-lyrics/vue";
import { ref } from "vue";

const lyricLines = ref<LyricLine[]>([]);
</script>
```

`lyricLines` 可以使用 Vue 的普通 `ref`。Vue 绑定会在将数据传递给 Core
组件前解除响应式代理。
12 changes: 9 additions & 3 deletions packages/vue/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,18 @@ For detailed API documentation, please refer to [AMLL Docs](https://amll.dev/en/
A test program can be found in [../playground/vue/src/test.ts](../playground/vue/src/test.ts).

```vue
<tamplate>
<LyricPlayer :lyric-lines="[]" :current-time="0" />
</tamplate>
<template>
<LyricPlayer :lyric-lines="lyricLines" :current-time="0" />
</template>

<script setup lang="ts">
import type { LyricLine } from "@applemusic-like-lyrics/core";
import { LyricPlayer } from "@applemusic-like-lyrics/vue";
import { ref } from "vue";

const lyricLines = ref<LyricLine[]>([]);
</script>
```

`lyricLines` can use Vue's regular `ref`. The Vue binding unwraps reactive
proxies before passing the data to the Core component.
4 changes: 3 additions & 1 deletion packages/vue/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"build": "run-p typecheck \"build-only {@}\" --",
"build:dev": "tsdown",
"fmt": "biome format --write ./src",
"test": "vitest test",
"dev": "nx run @applemusic-like-lyrics/playground-vue:dev"
},
"main": "./dist/amll-vue.cjs",
Expand Down Expand Up @@ -66,6 +67,7 @@
"tsdown": "catalog:",
"typedoc": "^0.28.17",
"typedoc-plugin-markdown": "catalog:",
"vue": "^3.5.41"
"vue": "^3.5.41",
"vitest": "catalog:"
}
}
3 changes: 2 additions & 1 deletion packages/vue/src/LyricPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
watch,
watchEffect,
} from "vue";
import { unwrapLyricLines } from "./utils/unwrap-lyric-lines";

const lyricPlayerProps = {
/**
Expand Down Expand Up @@ -297,7 +298,7 @@ export const LyricPlayer = defineComponent({
maskMode: props.maskObsceneWordsMode,
maskChar: props.maskObsceneWordChar,
});
player.setLyricLines(lyricLines ?? []);
player.setLyricLines(unwrapLyricLines(lyricLines));

if (props.currentTime !== undefined) {
player.setCurrentTime(props.currentTime, true);
Expand Down
8 changes: 8 additions & 0 deletions packages/vue/src/utils/unwrap-lyric-lines.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { LyricLine } from "@applemusic-like-lyrics/core";
import { toRaw } from "vue";

export function unwrapLyricLines(
lyricLines: LyricLine[] | undefined,
): LyricLine[] {
return toRaw(lyricLines ?? []);
}
31 changes: 31 additions & 0 deletions packages/vue/test/reactive-lyric-lines.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { LyricLine } from "@applemusic-like-lyrics/core";
import { describe, expect, it } from "vitest";
import { isProxy, ref } from "vue";
import { unwrapLyricLines } from "../src/utils/unwrap-lyric-lines";

function createLine(): LyricLine {
return {
words: [{ word: "test", startTime: 0, endTime: 1000 }],
translatedLyric: "",
romanLyric: "",
startTime: 0,
endTime: 1000,
isBG: false,
isDuet: false,
};
}

describe("unwrapLyricLines", () => {
it("unwraps deeply reactive lyric lines before passing them to core", () => {
const lyricLines = ref<LyricLine[]>([createLine()]);

expect(isProxy(lyricLines.value)).toBe(true);
expect(isProxy(lyricLines.value[0])).toBe(true);

const unwrapped = unwrapLyricLines(lyricLines.value);

expect(isProxy(unwrapped)).toBe(false);
expect(isProxy(unwrapped[0])).toBe(false);
expect(() => structuredClone(unwrapped)).not.toThrow();
});
});
2 changes: 1 addition & 1 deletion packages/vue/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"extends": "../../tsconfig.base.json",
"include": ["src"],
"include": ["src", "test"],
"compilerOptions": {
// vue 的类型系统非常复杂,基本无法手动定义出来
"isolatedDeclarations": false,
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.