mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-16 01:26:16 -08:00
fix(site): [SITE-VCONSOLE-01] cancel stale console lifecycle work
This commit is contained in:
1 parent
838c3eb432
commit
e7f31b6fc8
22 files changed
+2318
-32
No files matched your search
@@ -0,0 +1,12 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
import process from 'node:process'
|
||||
import { generateVconsole } from './site-vendor/vconsole/build.ts'
|
||||
|
||||
assert(process.argv.slice(2).every(arg => arg === '--check'), 'Use yarn build:vconsole [--check]')
|
||||
const candidate = await generateVconsole(process.cwd())
|
||||
const output = 'docs/assets/js/vconsole.min.js'
|
||||
if (process.argv.includes('--check'))
|
||||
assert.equal(fs.readFileSync(output, 'utf8'), candidate, 'Generated vConsole lifecycle patch drift')
|
||||
else fs.writeFileSync(output, candidate)
|
||||
console.log('vConsole 3.15.0 lifecycle patch generated/checked; upstream code outside the six pinned insertion points is retained.')
|
||||
@@ -29,11 +29,11 @@ own fingerprinted site. `.gitattributes` preserves text bytes across Windows/Lin
|
||||
`yarn test:site-notices` tests missing/extra/modified assets, changed or incomplete
|
||||
inputs, path escape and read-only output drift. The browser fixture
|
||||
`test/browser/site-vendor.spec.js` checks actual mobile logging, native playback,
|
||||
HTTP notice contents and destruction. Its WebKit destruction error is a real
|
||||
open vendor issue; do not skip the test or catch the page error to turn it green.
|
||||
HTTP notice contents and destruction. The fixed-source lifecycle patch and its
|
||||
old-build reproduction are maintained in `vconsole/README.md`; generated asset
|
||||
checks run before the notice checks. Do not skip destruction or catch page errors.
|
||||
Existing desktop TypeScript editor tests cover the real Monaco worker and Run.
|
||||
|
||||
Follow-up: reproduce the pending vConsole log-store callback after destruction,
|
||||
restore complete licensing from fixed upstream evidence, then recover the
|
||||
Follow-up: restore complete licensing from fixed upstream evidence, then recover the
|
||||
console.js build and resolve remaining fonts/media. Do not upgrade these assets
|
||||
without verifying globals, AMD/worker paths, CSS, consoleLog and user interaction.
|
||||
@@ -16,8 +16,9 @@
|
||||
"path": "docs/assets/js/vconsole.min.js",
|
||||
"member": "package/dist/vconsole.min.js",
|
||||
"upstreamSha256": "671f47427e1e3048919147c765e9fb71e4ea40d79a8c2829089f499d3e9b9bf4",
|
||||
"sha256": "671f47427e1e3048919147c765e9fb71e4ea40d79a8c2829089f499d3e9b9bf4",
|
||||
"mode": "lf-text"
|
||||
"sha256": "3d1b8c3aff5f415ccf3bdc3cdcec6e01cff5b4c64d4558c078ca33d003f616ac",
|
||||
"mode": "lf-text",
|
||||
"patchSource": "scripts/site-vendor/vconsole/README.md"
|
||||
}
|
||||
],
|
||||
"notices": [
|
||||
@@ -27,7 +28,7 @@
|
||||
"sha256": "272588ba6d7c09d6c3bedf3601e37b2ede6d4539d28a9052fcc3038df99cf683"
|
||||
}
|
||||
],
|
||||
"review": "The 3.15.0 upstream LICENSE declares MIT but omits the promised full license text. The copied file preserves this upstream evidence; completeness and bundled dependency notices remain under review."
|
||||
"review": "The 3.15.0 upstream LICENSE declares MIT but omits the promised full license text. The copied file preserves this upstream evidence; completeness and bundled dependency notices remain under review. ArtPlayer applies a reproducible local lifecycle patch to log frame cancellation and delayed panel ownership; the upstream bundle is frozen in scripts/site-vendor/vconsole/upstream.js and generated by yarn build:vconsole. Public asset URL and UMD/CSS contracts are retained."
|
||||
},
|
||||
{
|
||||
"name": "monaco-editor",
|
||||
|
||||
@@ -30,7 +30,7 @@ function list(root: string, relative: string): string[] {
|
||||
export function generateNotices(root: string, manifest: VendorManifest): Map<string, Uint8Array> {
|
||||
assert.equal(manifest.schemaVersion, 1)
|
||||
const outputs = new Map<string, Uint8Array>()
|
||||
const summary = ['# Verified site component notices', '', manifest.scope, '', 'Generated by yarn build:site-notices. Runtime asset URLs and bytes are unchanged.', '']
|
||||
const summary = ['# Verified site component notices', '', manifest.scope, '', 'Generated by yarn build:site-notices. Runtime asset URLs are retained; reviewed local patches are identified below.', '']
|
||||
for (const group of manifest.groups) {
|
||||
assert(group.notices.length > 0, `Missing upstream notice sources: ${group.name}`)
|
||||
const actual = group.roots.flatMap(relative => list(root, relative)).sort()
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# vConsole lifecycle patch
|
||||
|
||||
The public `docs/assets/js/vconsole.min.js` URL remains vConsole 3.15.0 with a
|
||||
local lifecycle correction. `upstream.js` is the exact npm distribution bundle:
|
||||
SHA-256 `671f47427e1e3048919147c765e9fb71e4ea40d79a8c2829089f499d3e9b9bf4`.
|
||||
The archive identity and upstream LICENSE are pinned in `../manifest.json`.
|
||||
Reference source is Tencent/vConsole commit
|
||||
`05d80398bae35e793774f74e3c052b4e530e293a` (tag v3.15.0):
|
||||
`src/log/log.model.ts`, `src/core/core.ts`, and
|
||||
`src/component/recycleScroller/recycleScroller.svelte`.
|
||||
|
||||
## Ownership and build
|
||||
|
||||
- `lifecycle.ts` owns queued log frames. Removing the last log plugin invalidates
|
||||
the ticket before cancellation, clears its queue/flag, and restores console
|
||||
even when cancellation throws. A late cancelled callback cannot consume a new
|
||||
queue on the reused singleton log model. Ordinary batches retain order and
|
||||
release their flag before flushing, including reentrant logging.
|
||||
- The same helper schedules panel insertion against the original instance and
|
||||
plugin object. Removed or replaced plugins cannot populate a new same-ID tab.
|
||||
- `build.ts` verifies the whole upstream SHA and six unique insertion points.
|
||||
It adds the private helper inside the existing UMD factory, replaces log
|
||||
scheduling/unbinding and panel insertion, and guards two virtual-scroller
|
||||
continuations after their timers. Svelte sets the bound items element to null
|
||||
on destroy; those continuations return before touching removed DOM.
|
||||
- `../../build-vconsole.mjs` (`scripts/build-vconsole.mjs` from the root)
|
||||
is the CLI. TypeScript and esbuild are existing root dev dependencies. The
|
||||
helper is emitted as ES5; it uses an array rather than requiring WeakMap before
|
||||
the upstream bundle installs its own polyfills. The remaining vendor code,
|
||||
CSS and UMD branch selection are retained byte for byte.
|
||||
|
||||
Run `yarn build:vconsole` after editing the helper or reviewed patch hooks, then
|
||||
update the candidate fingerprint in `../manifest.json` and
|
||||
`refactor/third-party.json` with the validation evidence. Run
|
||||
`yarn build:site-notices`. `yarn check:vconsole` is read-only and rejects output
|
||||
drift; it does not update the frozen upstream or bless arbitrary vendor changes.
|
||||
CI checks generation before notices and rebuilds the patch before notice output.
|
||||
Never hand-edit the generated minified file.
|
||||
|
||||
## Validation and limits
|
||||
|
||||
`yarn test:vconsole` covers queue order, reentrancy, cancellation exceptions,
|
||||
late callbacks, panel ownership, upstream drift and deterministic generation.
|
||||
`yarn test:browser test/browser/vconsole-lifecycle.spec.js test/browser/site-vendor.spec.js --workers=1`
|
||||
covers real browser globals, named AMD, CommonJS factory loading, visible logs,
|
||||
immediate destroy/recreate, same-ID plugin replacement, pending scroller layout,
|
||||
and the actual mobile page playing local media. Setting
|
||||
`ARTPLAYER_VCONSOLE_BASELINE=1` serves the frozen original only in the lifecycle
|
||||
test to reproduce failures; normal CI serves the candidate and expects no errors.
|
||||
The scroller case holds zero-delay timers to force the late continuation while
|
||||
using native rendering, ResizeObserver and RAF; this is explicit fault injection.
|
||||
|
||||
This patch does not claim complete upstream lifecycle coverage, device coverage,
|
||||
or permission clearance. The upstream LICENSE is distributed verbatim, but its
|
||||
missing MIT body and bundled dependency notices remain open in VENDOR-07/SITE-07.
|
||||
Do not replace or upgrade the bundle to resolve these issues without separately
|
||||
checking entrypoints, logging, CSS and the full dependency notices.
|
||||
@@ -0,0 +1,40 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { createHash } from 'node:crypto'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { build } from 'esbuild'
|
||||
import ts from 'typescript'
|
||||
|
||||
export const upstreamSha256 = '671f47427e1e3048919147c765e9fb71e4ea40d79a8c2829089f499d3e9b9bf4'
|
||||
export const hooks = {
|
||||
factory: '(this||self,(function(){return function(){',
|
||||
signal: 'e._signalLog=function(t){var n=this;this.flushLogScheduled||(this.flushLogScheduled=!0,window.requestAnimationFrame((function(){n.flushLogScheduled=!1,n._flushLogs()}))),this.logQueue.push(t)}',
|
||||
unbind: '0===this.ADDED_LOG_PLUGIN_ID.length&&this.unmockConsole()',
|
||||
panel: 'o&&setTimeout((function(){var e=document.querySelector("#__vc_plug_"+t.id);n.HD(o)?e.innerHTML+=o:n.mf(o.appendTo)?o.appendTo(e):n.kK(o)&&e.insertAdjacentElement("beforeend",o)}),0)',
|
||||
resizeResume: 'case 9:F(p),X(p,W.getPosition(),k),0!==k&&H(N&&L),K();',
|
||||
itemResume: 'case 12:X(p,W.getPosition(),k),e(6,s.style.height=P+"px",s),K();',
|
||||
}
|
||||
|
||||
function replaceOne(source: string, from: string, to: string): string {
|
||||
assert.equal(source.split(from).length, 2, 'Frozen vConsole hook must occur exactly once')
|
||||
return source.replace(from, to)
|
||||
}
|
||||
|
||||
export async function generateVconsole(root: string): Promise<string> {
|
||||
const directory = path.join(root, 'scripts/site-vendor/vconsole')
|
||||
const upstream = fs.readFileSync(path.join(directory, 'upstream.js'), 'utf8')
|
||||
assert.equal(createHash('sha256').update(upstream).digest('hex'), upstreamSha256, 'Frozen vConsole source changed')
|
||||
const source = fs.readFileSync(path.join(directory, 'lifecycle.ts'), 'utf8')
|
||||
const compiled = ts.transpileModule(source, { compilerOptions: { target: ts.ScriptTarget.ES5, module: ts.ModuleKind.ESNext } }).outputText
|
||||
const result = await build({ stdin: { contents: compiled, loader: 'js' }, bundle: true, write: false, platform: 'browser', format: 'iife', globalName: '__artplayerVConsoleLogLifecycle', target: 'es5', minify: true, legalComments: 'none', logLevel: 'silent' })
|
||||
const helper = result.outputFiles?.[0]?.text.trim()
|
||||
assert(helper, 'Missing vConsole lifecycle helper')
|
||||
let candidate = replaceOne(upstream, hooks.signal, 'e._signalLog=function(t){__artplayerVConsoleLogLifecycle.enqueue(this,t,window)}')
|
||||
candidate = replaceOne(candidate, hooks.unbind, '0===this.ADDED_LOG_PLUGIN_ID.length&&__artplayerVConsoleLogLifecycle.unbind(this,window)')
|
||||
candidate = replaceOne(candidate, hooks.panel, 'o&&__artplayerVConsoleLogLifecycle.renderTab(e,t,(function(){var e=document.querySelector("#__vc_plug_"+t.id);n.HD(o)?e.innerHTML+=o:n.mf(o.appendTo)?o.appendTo(e):n.kK(o)&&e.insertAdjacentElement("beforeend",o)}))')
|
||||
// Svelte clears the bound items element on destroy; these continuations resume after a timer.
|
||||
candidate = replaceOne(candidate, hooks.resizeResume, 'case 9:if(!s)return n.abrupt("return");F(p),X(p,W.getPosition(),k),0!==k&&H(N&&L),K();')
|
||||
candidate = replaceOne(candidate, hooks.itemResume, 'case 12:if(!s)return o.abrupt("return");X(p,W.getPosition(),k),e(6,s.style.height=P+"px",s),K();')
|
||||
candidate = replaceOne(candidate, hooks.factory, `(this||self,(function(){${helper}return function(){`)
|
||||
return candidate
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
interface LogHost {
|
||||
ADDED_LOG_PLUGIN_ID: string[]
|
||||
flushLogScheduled: boolean
|
||||
logQueue: unknown[]
|
||||
_flushLogs: () => void
|
||||
unmockConsole: () => void
|
||||
}
|
||||
interface Frames {
|
||||
requestAnimationFrame: (callback: FrameRequestCallback) => number
|
||||
cancelAnimationFrame: (id: number) => void
|
||||
}
|
||||
const pending: { host: LogHost, id: number }[] = []
|
||||
|
||||
interface PanelHost {
|
||||
isInited: boolean
|
||||
pluginList: Record<string, { id: string }>
|
||||
}
|
||||
|
||||
export function renderTab(host: PanelHost, plugin: { id: string }, render: () => void): void {
|
||||
setTimeout(() => {
|
||||
if (host.isInited && host.pluginList[plugin.id] === plugin)
|
||||
render()
|
||||
}, 0)
|
||||
}
|
||||
|
||||
export function enqueue(host: LogHost, log: unknown, frames: Frames): void {
|
||||
if (host.ADDED_LOG_PLUGIN_ID.length === 0)
|
||||
return
|
||||
if (!host.flushLogScheduled) {
|
||||
const ticket = { host, id: 0 }
|
||||
pending.push(ticket)
|
||||
host.flushLogScheduled = true
|
||||
ticket.id = frames.requestAnimationFrame(() => {
|
||||
const index = pending.indexOf(ticket)
|
||||
if (index === -1)
|
||||
return
|
||||
pending.splice(index, 1)
|
||||
host.flushLogScheduled = false
|
||||
host._flushLogs()
|
||||
})
|
||||
}
|
||||
host.logQueue.push(log)
|
||||
}
|
||||
|
||||
export function unbind(host: LogHost, frames: Frames): void {
|
||||
let ticket
|
||||
for (let index = 0; index < pending.length; index++) {
|
||||
if (pending[index]!.host === host) {
|
||||
ticket = pending[index]
|
||||
pending.splice(index, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
host.logQueue = []
|
||||
host.flushLogScheduled = false
|
||||
try {
|
||||
if (ticket && typeof frames.cancelAnimationFrame === 'function')
|
||||
frames.cancelAnimationFrame(ticket.id)
|
||||
}
|
||||
finally {
|
||||
host.unmockConsole()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/*!
|
||||
* vConsole v3.15.0 (https://github.com/Tencent/vConsole)
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making vConsole available.
|
||||
* Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define("VConsole",[],n):"object"==typeof exports?exports.VConsole=n():t.VConsole=n()}(this||self,(function(){return function(){var __webpack_modules__={4264:function(t,n,e){t.exports=e(7588)},5036:function(t,n,e){e(1719),e(5677),e(6394),e(5334),e(6969),e(2021),e(8328),e(2129);var o=e(1287);t.exports=o.Promise},2582:function(t,n,e){e(1646),e(6394),e(2004),e(462),e(8407),e(2429),e(1172),e(8288),e(1274),e(8201),e(6626),e(3211),e(9952),e(15),e(9831),e(7521),e(2972),e(6956),e(5222),e(2257);var o=e(1287);t.exports=o.Symbol},8257:function(t,n,e){var o=e(7583),r=e(9212),i=e(5637),a=o.TypeError;t.exports=function(t){if(r(t))return t;throw a(i(t)+" is not a function")}},1186:function(t,n,e){var o=e(7583),r=e(2097),i=e(5637),a=o.TypeError;t.exports=function(t){if(r(t))return t;throw a(i(t)+" is not a constructor")}},9882:function(t,n,e){var o=e(7583),r=e(9212),i=o.String,a=o.TypeError;t.exports=function(t){if("object"==typeof t||r(t))return t;throw a("Can't set "+i(t)+" as a prototype")}},6288:function(t,n,e){var o=e(3649),r=e(3590),i=e(4615),a=o("unscopables"),c=Array.prototype;null==c[a]&&i.f(c,a,{configurable:!0,value:r(null)}),t.exports=function(t){c[a][t]=!0}},4761:function(t,n,e){var o=e(7583),r=e(2447),i=o.TypeError;t.exports=function(t,n){if(r(n,t))return t;throw i("Incorrect invocation")}},2569:function(t,n,e){var o=e(7583),r=e(794),i=o.String,a=o.TypeError;t.exports=function(t){if(r(t))return t;throw a(i(t)+" is not an object")}},5766:function(t,n,e){var o=e(2977),r=e(6782),i=e(1825),a=function(t){return function(n,e,a){var c,u=o(n),s=i(u),l=r(a,s);if(t&&e!=e){for(;s>l;)if((c=u[l++])!=c)return!0}else for(;s>l;l++)if((t||l in u)&&u[l]===e)return t||l||0;return!t&&-1}};t.exports={includes:a(!0),indexOf:a(!1)}},4805:function(t,n,e){var o=e(2938),r=e(7386),i=e(5044),a=e(1324),c=e(1825),u=e(4822),s=r([].push),l=function(t){var n=1==t,e=2==t,r=3==t,l=4==t,f=6==t,d=7==t,v=5==t||f;return function(h,p,g,m){for(var _,b,y=a(h),w=i(y),E=o(p,g),L=c(w),T=0,x=m||u,C=n?x(h,L):e||d?x(h,0):void 0;L>T;T++)if((v||T in w)&&(b=E(_=w[T],T,y),t))if(n)C[T]=b;else if(b)switch(t){case 3:return!0;case 5:return _;case 6:return T;case 2:s(C,_)}else switch(t){case 4:return!1;case 7:s(C,_)}return f?-1:r||l?l:C}};t.exports={forEach:l(0),map:l(1),filter:l(2),some:l(3),every:l(4),find:l(5),findIndex:l(6),filterReject:l(7)}},9269:function(t,n,e){var o=e(6544),r=e(3649),i=e(4061),a=r("species");t.exports=function(t){return i>=51||!o((function(){var n=[];return(n.constructor={})[a]=function(){return{foo:1}},1!==n[t](Boolean).foo}))}},4546:function(t,n,e){var o=e(7583),r=e(6782),i=e(1825),a=e(5999),c=o.Array,u=Math.max;t.exports=function(t,n,e){for(var o=i(t),s=r(n,o),l=r(void 0===e?o:e,o),f=c(u(l-s,0)),d=0;s<l;s++,d++)a(f,d,t[s]);return f.length=d,f}},6917:function(t,n,e){var o=e(7386);t.exports=o([].slice)},5289:function(t,n,e){var o=e(7583),r=e(4521),i=e(2097),a=e(794),c=e(3649)("species"),u=o.Array;t.exports=function(t){var n;return r(t)&&(n=t.constructor,(i(n)&&(n===u||r(n.prototype))||a(n)&&null===(n=n[c]))&&(n=void 0)),void 0===n?u:n}},4822:function(t,n,e){var o=e(5289);t.exports=function(t,n){return new(o(t))(0===n?0:n)}},3616:function(t,n,e){var o=e(3649)("iterator"),r=!1;try{var i=0,a={next:function(){return{done:!!i++}},return:function(){r=!0}};a[o]=function(){return this},Array.from(a,(function(){throw 2}))}catch(t){}t.exports=function(t,n){if(!n&&!r)return!1;var e=!1;try{var i={};i[o]=function(){return{next:function(){return{done:e=!0}}}},t(i)}catch(t){}return e}},9624:function(t,n,e){var o=e(7386),r=o({}.toString),i=o("".slice);t.exports=function(t){return i(r(t),8,-1)}},3058:function(t,n,e){var o=e(7583),r=e(8191),i=e(9212),a=e(9624),c=e(3649)("toStringTag"),u=o.Object,s="Arguments"==a(function(){return arguments}());t.exports=r?a:function(t){var n,e,o;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(e=function(t,n){try{return t[n]}catch(t){}}(n=u(t),c))?e:s?a(n):"Object"==(o=a(n))&&i(n.callee)?"Arguments":o}},1509:function(t,n,e){var o=e(7386)("".replace),r=String(Error("zxcasd").stack),i=/\n\s*at [^:]*:[^\n]*/,a=i.test(r);t.exports=function(t,n){if(a&&"string"==typeof t)for(;n--;)t=o(t,i,"");return t}},3478:function(t,n,e){var o=e(2870),r=e(929),i=e(6683),a=e(4615);t.exports=function(t,n,e){for(var c=r(n),u=a.f,s=i.f,l=0;l<c.length;l++){var f=c[l];o(t,f)||e&&o(e,f)||u(t,f,s(n,f))}}},926:function(t,n,e){var o=e(6544);t.exports=!o((function(){function t(){}return t.prototype.constructor=null,Object.getPrototypeOf(new t)!==t.prototype}))},4683:function(t,n,e){"use strict";var o=e(2365).IteratorPrototype,r=e(3590),i=e(4677),a=e(8821),c=e(339),u=function(){return this};t.exports=function(t,n,e,s){var l=n+" Iterator";return t.prototype=r(o,{next:i(+!s,e)}),a(t,l,!1,!0),c[l]=u,t}},57:function(t,n,e){var o=e(8494),r=e(4615),i=e(4677);t.exports=o?function(t,n,e){return r.f(t,n,i(1,e))}:function(t,n,e){reLine truncated
|
||||
@@ -28,6 +28,7 @@
|
||||
"build-site-notices.mjs",
|
||||
"build-i18n.js",
|
||||
"build-docs.js",
|
||||
"../packages/artplayer-vitepress/build/**/*.ts"
|
||||
"../packages/artplayer-vitepress/build/**/*.ts",
|
||||
"build-vconsole.mjs"
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user