히스토리 팝업에 제목이 잘못 표시됨 (Firefox)

안녕하세요,
Firefox에서 “이전 페이지” 화살표에 우클릭했을 때 표시되는 이전 페이지 제목이 현재 페이지 제목으로 덮어쓰기됩니다.

예를 들어, 처음 표시된 페이지가 다음과 같은 경우:
https://meta.discourse.org/
화살표에 우클릭했을 때의 모습을 확인해 보세요(정상적으로 표시됩니다):

그런 다음 어떤 주제(예: DiscoTOC - automatic table of contents)로 이동하면, 이전 페이지의 제목이 현재 페이지 제목으로 덮어쓰기됩니다:

그럼에도 불구하고 링크는 여전히 유효합니다.

이 버그에 대해 혹시 아는 게 있나요?

역사를 대체하는 방식 또는 순서에서, 혹은 Firefox의 특이한 동작에서 발생하는 버그로 보입니다.

재현이 가능합니다.

상당히 경미한 문제이므로, 커뮤니티에서 기여하여 수정안을 제안할 수 있도록 pr-welcome 라벨을 붙일 예정입니다.

네, 답변해 주셔서 감사합니다

이 버그가 브라우저 히스토리의 항목이 다소 손상된 형태로 나타나는 문제이기도 하다는 것을 발견했습니다. 저는 이를 더 심각한 문제로 보고 있습니다. 구체적으로, 네비게이션이 JS에 의해 처리될 때 오래된 URL에 새로운 제목이 할당되는 현상입니다. 이는 Firefox에서는 거의 항상 발생하지만 Chrome에서는 매우 드뭅니다(현재까지 발견한 사례는 하나입니다: /top에서 특정 토픽으로 이동할 때).

@sam 님의 지적처럼, 이는 URL과 제목이 수정되는 작업 순서 때문에 발생하는 문제입니다. URL과 제목의 올바른 수정 순서를 명시한 모종의 모범 사례 가이드가 어딘가에 공개되어 있기를 바랍니다: history API를 사용한 이후에 항상 제목을 업데이트해야 한다는 것 말이죠.

디버깅을 시도해 보았습니다(미리 말씀드리자면, 저는 중간 규모 이상의 npm 관련 프로젝트를 구축하는 것에 대해 상당한 거부감을 가지고 있습니다). 처음에는 다음 코드를 사용하여 간단한 정찰을 수행했습니다:

Object.defineProperty(document, "title", {
  get() {
    return document.head.querySelector('title').innerText;
  },
  set(t) {
    console.debug('title', t, new Error("title!").stack)
    debugger;
    document.head.querySelector('title').innerText = t;
  },
  enumerable: true,
  configurable: true,
});
let ___push___ = window.history.pushState;
window.history.pushState = function(...args) {
  console.debug('push', args[0], new Error().stack);
  debugger;
  ___push___.apply(this, args);
};

let ___replace___ = window.history.replaceState;
window.history.replaceState = function(...args) {
  console.debug('replace', args[0], new Error().stack);
  debugger;
  ___replace___.apply(this, args);
};

실제로 history API 작업 직전에 제목이 거의 항상 한 번 수정되는 것이 확인되었습니다. 불행히도 그 이상의 도움은 되지 않았습니다: 런타임에서 일어나는 일을 소스 코드와 연결하는 것은 상당히 어려웠습니다 – 관심 있는 작업들이 상당히 분산되어 있었고, 호출 스택은 이미 Ember의 이벤트 루프로 실행이 양도되었기 때문에 혼란을 주었으며, 전반적으로 Firefox에서의 디버깅 경험은 매우 고통스러웠습니다. Chrome으로 전환한 후에는 조금 더 성공적이었습니다. 결론부터 말하자면, AFAIK(제가 아는 한) Ember는 URL을 업데이트할 시점을 스스로 결정합니다. 반면, 제목 수정은 두 곳에서 시작될 수 있습니다: [1]과 [2]

그중 후자만 history API 호출 전에 실행됩니다. 이 두 곳의 '공통 코드 조상’은 여기에 위치해 있습니다:

// Run all the necessary enter/setup/exit hooks
this.setupContexts(newState, transition); // <- title change initiated here, by triggering `model.title:change` event

// Check if a redirect occurred in enter/setup
if (transition.isAborted) {
  // TODO: cleaner way? distinguish b/w targetRouteInfos?
  this.state!.routeInfos = this.currentRouteInfos!;
  return Promise.reject(logAbort(transition));
}

this._updateURL(transition, newState); // <- url change initiated here

흥미롭게도, "router.js는 Ember.js에서 사용되는 라우팅 마이크로 라이브러리"입니다.

이제 저는 이 문제의 처리를, 저와 달리 discourse 코드베이스에 어느 정도 익숙한 누군가에게 넘기고 싶습니다.

수정: 언급을 잊었습니다: document.title은 [2]에서 수정된 후와 history API에 의해 URL이 수정된 후에도 [1]에서 한 번 이상 수정됩니다.

1개의 좋아요

(신규 사용자는 게시글에 링크를 2개 이상 올릴 수 없어요 :frowning: )

[1] (discourse/app/assets/javascripts/discourse/app/lib/page-tracker.js at 245e9f30a4825beb86fcbfcf718208752748e5b4 · discourse/discourse · GitHub)

[2] (discourse/app/assets/javascripts/discourse/app/controllers/topic.js at 542f77181a47df8aa0f909f69814406491d08c5e · discourse/discourse · GitHub)

1개의 좋아요