Update dev-tools.js
Browse files- dev-tools.js +0 -267
dev-tools.js
CHANGED
@@ -6,31 +6,8 @@
|
|
6 |
let dtActiveEditElement = null;
|
7 |
let dtNetworkRequests = [];
|
8 |
let dtSelectedRequest = null;
|
9 |
-
let dtVitalsData = {
|
10 |
-
CLS: null,
|
11 |
-
FCP: null,
|
12 |
-
FID: null,
|
13 |
-
LCP: null,
|
14 |
-
TTFB: null
|
15 |
-
};
|
16 |
let dtObserver = null;
|
17 |
let dtRefreshElementsPanel = null;
|
18 |
-
let dtVitalsMeasurementStarted = false;
|
19 |
-
|
20 |
-
// Web Vitalsスクリプトを動的に読み込み
|
21 |
-
const loadWebVitals = () => {
|
22 |
-
return new Promise((resolve) => {
|
23 |
-
if (window.webVitals) {
|
24 |
-
resolve();
|
25 |
-
return;
|
26 |
-
}
|
27 |
-
|
28 |
-
const webVitalsScript = document.createElement('script');
|
29 |
-
webVitalsScript.src = 'https://unpkg.com/[email protected]/dist/web-vitals.iife.js';
|
30 |
-
webVitalsScript.onload = resolve;
|
31 |
-
document.head.appendChild(webVitalsScript);
|
32 |
-
});
|
33 |
-
};
|
34 |
|
35 |
// DOM変更を監視するMutationObserver (最適化版)
|
36 |
const setupMutationObserver = () => {
|
@@ -461,69 +438,6 @@
|
|
461 |
overflow-y: auto;
|
462 |
}
|
463 |
|
464 |
-
/* Web Vitals スタイル */
|
465 |
-
.dt-vitals-container {
|
466 |
-
display: flex;
|
467 |
-
flex-direction: column;
|
468 |
-
gap: 15px;
|
469 |
-
}
|
470 |
-
|
471 |
-
.dt-vital-card {
|
472 |
-
background: var(--dt-tab-bg);
|
473 |
-
border: 1px solid var(--dt-border-color);
|
474 |
-
border-radius: 5px;
|
475 |
-
padding: 15px;
|
476 |
-
}
|
477 |
-
|
478 |
-
.dt-vital-title {
|
479 |
-
font-weight: bold;
|
480 |
-
margin-bottom: 10px;
|
481 |
-
color: var(--dt-primary-color);
|
482 |
-
display: flex;
|
483 |
-
justify-content: space-between;
|
484 |
-
align-items: center;
|
485 |
-
}
|
486 |
-
|
487 |
-
.dt-vital-value {
|
488 |
-
font-size: 24px;
|
489 |
-
font-weight: bold;
|
490 |
-
margin: 10px 0;
|
491 |
-
}
|
492 |
-
|
493 |
-
.dt-vital-good {
|
494 |
-
color: var(--dt-success-color);
|
495 |
-
}
|
496 |
-
|
497 |
-
.dt-vital-needs-improvement {
|
498 |
-
color: var(--dt-warning-color);
|
499 |
-
}
|
500 |
-
|
501 |
-
.dt-vital-poor {
|
502 |
-
color: var(--dt-error-color);
|
503 |
-
}
|
504 |
-
|
505 |
-
.dt-vital-description {
|
506 |
-
font-size: 13px;
|
507 |
-
color: var(--dt-text-muted);
|
508 |
-
}
|
509 |
-
|
510 |
-
.dt-vital-thresholds {
|
511 |
-
display: flex;
|
512 |
-
margin-top: 10px;
|
513 |
-
font-size: 12px;
|
514 |
-
}
|
515 |
-
|
516 |
-
.dt-vital-threshold {
|
517 |
-
flex: 1;
|
518 |
-
text-align: center;
|
519 |
-
padding: 5px;
|
520 |
-
border-radius: 3px;
|
521 |
-
}
|
522 |
-
|
523 |
-
.dt-vital-threshold.active {
|
524 |
-
background: rgba(0, 122, 204, 0.2);
|
525 |
-
}
|
526 |
-
|
527 |
/* DOM Tree Toggle */
|
528 |
.dt-dom-toggle {
|
529 |
position: absolute;
|
@@ -617,13 +531,11 @@
|
|
617 |
const elementsTab = createTab('Elements', 'elements');
|
618 |
const networkTab = createTab('Network', 'network');
|
619 |
const storageTab = createTab('Storage', 'storage');
|
620 |
-
const vitalsTab = createTab('Web Vitals', 'vitals');
|
621 |
|
622 |
tabs.appendChild(consoleTab);
|
623 |
tabs.appendChild(elementsTab);
|
624 |
tabs.appendChild(networkTab);
|
625 |
tabs.appendChild(storageTab);
|
626 |
-
tabs.appendChild(vitalsTab);
|
627 |
|
628 |
const closeBtn = document.createElement('button');
|
629 |
closeBtn.className = 'dt-devtools-close';
|
@@ -641,13 +553,11 @@
|
|
641 |
const elementsPanel = createElementsPanel();
|
642 |
const networkPanel = createNetworkPanel();
|
643 |
const storagePanel = createStoragePanel();
|
644 |
-
const vitalsPanel = createVitalsPanel();
|
645 |
|
646 |
content.appendChild(consolePanel);
|
647 |
content.appendChild(elementsPanel);
|
648 |
content.appendChild(networkPanel);
|
649 |
content.appendChild(storagePanel);
|
650 |
-
content.appendChild(vitalsPanel);
|
651 |
|
652 |
container.appendChild(header);
|
653 |
container.appendChild(content);
|
@@ -678,183 +588,6 @@
|
|
678 |
elementsTab.click();
|
679 |
};
|
680 |
|
681 |
-
// Web Vitalsパネル作成 (測定開始ボタンが押されるまで何もしない)
|
682 |
-
function createVitalsPanel() {
|
683 |
-
const panel = document.createElement('div');
|
684 |
-
panel.className = 'dt-devtools-panel';
|
685 |
-
panel.id = 'vitals-panel';
|
686 |
-
|
687 |
-
const container = document.createElement('div');
|
688 |
-
container.className = 'dt-vitals-container';
|
689 |
-
panel.appendChild(container);
|
690 |
-
|
691 |
-
// 測定開始ボタン
|
692 |
-
const startButton = document.createElement('button');
|
693 |
-
startButton.className = 'dt-add-btn';
|
694 |
-
startButton.textContent = '測定を開始';
|
695 |
-
startButton.onclick = startVitalsMeasurement;
|
696 |
-
container.appendChild(startButton);
|
697 |
-
|
698 |
-
// CLS (Cumulative Layout Shift)
|
699 |
-
const clsCard = document.createElement('div');
|
700 |
-
clsCard.className = 'dt-vital-card';
|
701 |
-
clsCard.innerHTML = `
|
702 |
-
<div class="dt-vital-title">CLS (Cumulative Layout Shift) <span class="dt-vital-description">視覚的な安定性</span></div>
|
703 |
-
<div class="dt-vital-value" id="dt-cls-value">-</div>
|
704 |
-
<div class="dt-vital-thresholds">
|
705 |
-
<div class="dt-vital-threshold">Good: < 0.1</div>
|
706 |
-
<div class="dt-vital-threshold">Needs Improvement: < 0.25</div>
|
707 |
-
<div class="dt-vital-threshold">Poor: ≥ 0.25</div>
|
708 |
-
</div>
|
709 |
-
`;
|
710 |
-
container.appendChild(clsCard);
|
711 |
-
|
712 |
-
// FCP (First Contentful Paint)
|
713 |
-
const fcpCard = document.createElement('div');
|
714 |
-
fcpCard.className = 'dt-vital-card';
|
715 |
-
fcpCard.innerHTML = `
|
716 |
-
<div class="dt-vital-title">FCP (First Contentful Paint) <span class="dt-vital-description">最初のコンテンツ表示</span></div>
|
717 |
-
<div class="dt-vital-value" id="dt-fcp-value">-</div>
|
718 |
-
<div class="dt-vital-thresholds">
|
719 |
-
<div class="dt-vital-threshold">Good: < 1.8s</div>
|
720 |
-
<div class="dt-vital-threshold">Needs Improvement: < 3s</div>
|
721 |
-
<div class="dt-vital-threshold">Poor: ≥ 3s</div>
|
722 |
-
</div>
|
723 |
-
`;
|
724 |
-
container.appendChild(fcpCard);
|
725 |
-
|
726 |
-
// FID (First Input Delay)
|
727 |
-
const fidCard = document.createElement('div');
|
728 |
-
fidCard.className = 'dt-vital-card';
|
729 |
-
fidCard.innerHTML = `
|
730 |
-
<div class="dt-vital-title">FID (First Input Delay) <span class="dt-vital-description">最初の入力遅延</span></div>
|
731 |
-
<div class="dt-vital-value" id="dt-fid-value">-</div>
|
732 |
-
<div class="dt-vital-thresholds">
|
733 |
-
<div class="dt-vital-threshold">Good: < 100ms</div>
|
734 |
-
<div class="dt-vital-threshold">Needs Improvement: < 300ms</div>
|
735 |
-
<div class="dt-vital-threshold">Poor: ≥ 300ms</div>
|
736 |
-
</div>
|
737 |
-
`;
|
738 |
-
container.appendChild(fidCard);
|
739 |
-
|
740 |
-
// LCP (Largest Contentful Paint)
|
741 |
-
const lcpCard = document.createElement('div');
|
742 |
-
lcpCard.className = 'dt-vital-card';
|
743 |
-
lcpCard.innerHTML = `
|
744 |
-
<div class="dt-vital-title">LCP (Largest Contentful Paint) <span class="dt-vital-description">最大のコンテンツ表示</span></div>
|
745 |
-
<div class="dt-vital-value" id="dt-lcp-value">-</div>
|
746 |
-
<div class="dt-vital-thresholds">
|
747 |
-
<div class="dt-vital-threshold">Good: < 2.5s</div>
|
748 |
-
<div class="dt-vital-threshold">Needs Improvement: < 4s</div>
|
749 |
-
<div class="dt-vital-threshold">Poor: ≥ 4s</div>
|
750 |
-
</div>
|
751 |
-
`;
|
752 |
-
container.appendChild(lcpCard);
|
753 |
-
|
754 |
-
// TTFB (Time to First Byte)
|
755 |
-
const ttfbCard = document.createElement('div');
|
756 |
-
ttfbCard.className = 'dt-vital-card';
|
757 |
-
ttfbCard.innerHTML = `
|
758 |
-
<div class="dt-vital-title">TTFB (Time to First Byte) <span class="dt-vital-description">最初のバイト到達時間</span></div>
|
759 |
-
<div class="dt-vital-value" id="dt-ttfb-value">-</div>
|
760 |
-
<div class="dt-vital-thresholds">
|
761 |
-
<div class="dt-vital-threshold">Good: < 800ms</div>
|
762 |
-
<div class="dt-vital-threshold">Needs Improvement: < 1.8s</div>
|
763 |
-
<div class="dt-vital-threshold">Poor: ≥ 1.8s</div>
|
764 |
-
</div>
|
765 |
-
`;
|
766 |
-
container.appendChild(ttfbCard);
|
767 |
-
|
768 |
-
function startVitalsMeasurement() {
|
769 |
-
if (dtVitalsMeasurementStarted) return;
|
770 |
-
dtVitalsMeasurementStarted = true;
|
771 |
-
|
772 |
-
loadWebVitals().then(() => {
|
773 |
-
if (window.webVitals) {
|
774 |
-
try {
|
775 |
-
const vitals = window.webVitals;
|
776 |
-
if (vitals.getCLS) {
|
777 |
-
vitals.getCLS(updateCLS);
|
778 |
-
vitals.getFCP(updateFCP);
|
779 |
-
vitals.getFID(updateFID);
|
780 |
-
vitals.getLCP(updateLCP);
|
781 |
-
vitals.getTTFB(updateTTFB);
|
782 |
-
} else if (vitals.onCLS) {
|
783 |
-
vitals.onCLS(updateCLS);
|
784 |
-
vitals.onFCP(updateFCP);
|
785 |
-
vitals.onFID(updateFID);
|
786 |
-
vitals.onLCP(updateLCP);
|
787 |
-
vitals.onTTFB(updateTTFB);
|
788 |
-
}
|
789 |
-
startButton.textContent = '測定中...';
|
790 |
-
startButton.disabled = true;
|
791 |
-
} catch (e) {
|
792 |
-
console.error('Web Vitals error:', e);
|
793 |
-
}
|
794 |
-
}
|
795 |
-
});
|
796 |
-
}
|
797 |
-
|
798 |
-
function updateCLS(metric) {
|
799 |
-
dtVitalsData.CLS = metric.value;
|
800 |
-
updateVitalDisplay('cls', metric.value, 0.1, 0.25);
|
801 |
-
}
|
802 |
-
|
803 |
-
function updateFCP(metric) {
|
804 |
-
dtVitalsData.FCP = metric.value;
|
805 |
-
updateVitalDisplay('fcp', metric.value, 1800, 3000);
|
806 |
-
}
|
807 |
-
|
808 |
-
function updateFID(metric) {
|
809 |
-
dtVitalsData.FID = metric.value;
|
810 |
-
updateVitalDisplay('fid', metric.value, 100, 300);
|
811 |
-
}
|
812 |
-
|
813 |
-
function updateLCP(metric) {
|
814 |
-
dtVitalsData.LCP = metric.value;
|
815 |
-
updateVitalDisplay('lcp', metric.value, 2500, 4000);
|
816 |
-
}
|
817 |
-
|
818 |
-
function updateTTFB(metric) {
|
819 |
-
dtVitalsData.TTFB = metric.value;
|
820 |
-
updateVitalDisplay('ttfb', metric.value, 800, 1800);
|
821 |
-
}
|
822 |
-
|
823 |
-
function updateVitalDisplay(id, value, goodThreshold, needsImprovementThreshold) {
|
824 |
-
const element = document.getElementById(`dt-${id}-value`);
|
825 |
-
if (!element) return;
|
826 |
-
|
827 |
-
const displayValue = id === 'ttfb' ?
|
828 |
-
`${Math.round(value)}ms` :
|
829 |
-
`${value.toFixed(2)}${id === 'cls' ? '' : 's'}`;
|
830 |
-
|
831 |
-
element.textContent = displayValue;
|
832 |
-
|
833 |
-
element.className = 'dt-vital-value';
|
834 |
-
if (value <= goodThreshold) {
|
835 |
-
element.classList.add('dt-vital-good');
|
836 |
-
} else if (value <= needsImprovementThreshold) {
|
837 |
-
element.classList.add('dt-vital-needs-improvement');
|
838 |
-
} else {
|
839 |
-
element.classList.add('dt-vital-poor');
|
840 |
-
}
|
841 |
-
|
842 |
-
const thresholds = element.parentElement.querySelectorAll('.dt-vital-threshold');
|
843 |
-
thresholds.forEach((threshold, index) => {
|
844 |
-
threshold.classList.remove('active');
|
845 |
-
if (
|
846 |
-
(index === 0 && value <= goodThreshold) ||
|
847 |
-
(index === 1 && value > goodThreshold && value <= needsImprovementThreshold) ||
|
848 |
-
(index === 2 && value > needsImprovementThreshold)
|
849 |
-
) {
|
850 |
-
threshold.classList.add('active');
|
851 |
-
}
|
852 |
-
});
|
853 |
-
}
|
854 |
-
|
855 |
-
return panel;
|
856 |
-
}
|
857 |
-
|
858 |
// ネットワークパネル作成
|
859 |
function createNetworkPanel() {
|
860 |
const panel = document.createElement('div');
|
|
|
6 |
let dtActiveEditElement = null;
|
7 |
let dtNetworkRequests = [];
|
8 |
let dtSelectedRequest = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
let dtObserver = null;
|
10 |
let dtRefreshElementsPanel = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
|
12 |
// DOM変更を監視するMutationObserver (最適化版)
|
13 |
const setupMutationObserver = () => {
|
|
|
438 |
overflow-y: auto;
|
439 |
}
|
440 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
441 |
/* DOM Tree Toggle */
|
442 |
.dt-dom-toggle {
|
443 |
position: absolute;
|
|
|
531 |
const elementsTab = createTab('Elements', 'elements');
|
532 |
const networkTab = createTab('Network', 'network');
|
533 |
const storageTab = createTab('Storage', 'storage');
|
|
|
534 |
|
535 |
tabs.appendChild(consoleTab);
|
536 |
tabs.appendChild(elementsTab);
|
537 |
tabs.appendChild(networkTab);
|
538 |
tabs.appendChild(storageTab);
|
|
|
539 |
|
540 |
const closeBtn = document.createElement('button');
|
541 |
closeBtn.className = 'dt-devtools-close';
|
|
|
553 |
const elementsPanel = createElementsPanel();
|
554 |
const networkPanel = createNetworkPanel();
|
555 |
const storagePanel = createStoragePanel();
|
|
|
556 |
|
557 |
content.appendChild(consolePanel);
|
558 |
content.appendChild(elementsPanel);
|
559 |
content.appendChild(networkPanel);
|
560 |
content.appendChild(storagePanel);
|
|
|
561 |
|
562 |
container.appendChild(header);
|
563 |
container.appendChild(content);
|
|
|
588 |
elementsTab.click();
|
589 |
};
|
590 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
591 |
// ネットワークパネル作成
|
592 |
function createNetworkPanel() {
|
593 |
const panel = document.createElement('div');
|