Skip to content

Commit 625d194

Browse files
authored
vite: Emit initial start time telemetry for sku start (#1214)
1 parent e666d68 commit 625d194

File tree

7 files changed

+116
-1
lines changed

7 files changed

+116
-1
lines changed

.changeset/some-pugs-guess.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'sku': minor
3+
---
4+
5+
`vite`: Emit start time metric for `sku start`
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { viteService } from '@/services/vite/index.js';
22
import type { SkuContext } from '@/context/createSkuContext.js';
3+
import { metricsMeasurers } from '@/services/telemetry/metricsMeasurers.js';
34

45
export const viteStartHandler = async (skuContext: SkuContext) => {
56
await viteService.start(skuContext);
7+
8+
metricsMeasurers.skuStart.mark();
69
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import debug from 'debug';
2+
3+
const log = debug('sku:metrics');
4+
5+
const skuStartMarkName = 'skuStartComplete';
6+
const skuStart = {
7+
mark: () => {
8+
performance.mark(skuStartMarkName);
9+
},
10+
measure: () => {
11+
const result = performance.measure('skuStart', {}, skuStartMarkName);
12+
13+
log(`Sku dev server start took ${Math.round(result.duration)}ms`);
14+
15+
return result;
16+
},
17+
};
18+
19+
const initialPageLoadMarkName = 'initialPageLoadStart';
20+
const initialPageLoad = {
21+
mark: () => {
22+
performance.mark(initialPageLoadMarkName);
23+
},
24+
isInitialPageLoad: true,
25+
measure() {
26+
this.isInitialPageLoad = false;
27+
28+
const result = performance.measure(
29+
'initialPageLoad',
30+
initialPageLoadMarkName,
31+
);
32+
33+
log(`Initial page load took ${Math.round(result.duration)}ms`);
34+
35+
return result;
36+
},
37+
};
38+
39+
export const metricsMeasurers = {
40+
skuStart,
41+
initialPageLoad,
42+
};

packages/sku/src/services/vite/helpers/server/createViteServer.ts

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { SkuContext } from '@/context/createSkuContext.js';
44

55
import { createViteConfig } from '../createConfig.js';
66
import skuViteHMRTelemetryPlugin from '@/services/vite/plugins/skuViteHMRTelemetry.js';
7+
import { skuViteStartTelemetryPlugin } from '../../plugins/skuViteStartTelemetry.js';
78

89
export const createViteServer = async (skuContext: SkuContext) => {
910
const base = process.env.BASE || '/';
@@ -13,6 +14,10 @@ export const createViteServer = async (skuContext: SkuContext) => {
1314
skuContext,
1415
plugins: [
1516
skuViteMiddlewarePlugin(skuContext),
17+
skuViteStartTelemetryPlugin({
18+
target: 'node',
19+
type: 'static',
20+
}),
1621
skuViteHMRTelemetryPlugin({
1722
target: 'node',
1823
type: 'static',

packages/sku/src/services/vite/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ export const viteService = {
4141
const server = await createViteServerSsr({
4242
skuContext,
4343
});
44+
server.listen(skuContext.port.server);
4445

45-
await server.listen(skuContext.port.server);
4646
if (skuContext.sites.length > 1) {
4747
skuContext.sites.forEach((site) => {
4848
console.log(

packages/sku/src/services/vite/plugins/skuViteMiddlewarePlugin.ts

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { SkuContext } from '@/context/createSkuContext.js';
22
import type { Plugin } from 'vite';
33
import { createRequire } from 'node:module';
44
import type { ViteRenderFunction } from '@/types/types.js';
5+
import { metricsMeasurers } from '@/services/telemetry/metricsMeasurers.js';
56

67
const require = createRequire(import.meta.url);
78

@@ -10,6 +11,10 @@ export const skuViteMiddlewarePlugin = (skuContext: SkuContext): Plugin => ({
1011
configureServer(server) {
1112
return () => {
1213
server.middlewares.use(async (req, res, next) => {
14+
if (metricsMeasurers.initialPageLoad.isInitialPageLoad) {
15+
metricsMeasurers.initialPageLoad.mark();
16+
}
17+
1318
const host = req.headers.host;
1419
const hostname = host?.split(':')[0];
1520
const site =
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import type { Plugin } from 'vite';
2+
import js from 'dedent';
3+
import provider from '@/services/telemetry/index.js';
4+
import { metricsMeasurers } from '@/services/telemetry/metricsMeasurers.js';
5+
6+
const initialPageLoadEventName = 'sku:initialPageLoad' as const;
7+
8+
export const skuViteStartTelemetryPlugin = ({
9+
target,
10+
type,
11+
}: {
12+
target: string;
13+
type: string;
14+
}): Plugin => ({
15+
name: 'vite-plugin-sku-server-middleware',
16+
transformIndexHtml: {
17+
order: 'pre',
18+
handler: () => [
19+
{
20+
tag: 'script',
21+
attrs: {
22+
type: 'module',
23+
},
24+
children: skuPageLoadTelemetryClient,
25+
injectTo: 'head',
26+
},
27+
],
28+
},
29+
configureServer(server) {
30+
server.ws.on(initialPageLoadEventName, () => {
31+
if (metricsMeasurers.initialPageLoad.isInitialPageLoad) {
32+
const { duration: skuStartDuration } =
33+
metricsMeasurers.skuStart.measure();
34+
35+
const { duration: initialLoadDuration } =
36+
metricsMeasurers.initialPageLoad.measure();
37+
38+
const initialStartTime = skuStartDuration + initialLoadDuration;
39+
40+
provider.timing('start.webpack.initial', initialStartTime, {
41+
target,
42+
type,
43+
});
44+
}
45+
});
46+
},
47+
});
48+
49+
const skuPageLoadTelemetryClient = js/* js */ `
50+
addEventListener("load", () => {
51+
if (import.meta.hot) {
52+
import.meta.hot.send('${initialPageLoadEventName}');
53+
}
54+
})
55+
`;

0 commit comments

Comments
 (0)