mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-10 04:22:12 +00:00
docs(sveltekit): re-introduce speed insights (#9988)
This commit is contained in:
committed by
GitHub
parent
18ae78137c
commit
4280166df4
@@ -1,11 +1,10 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
extends: ['eslint:recommended', 'prettier'],
|
extends: ['eslint:recommended', 'plugin:svelte/recommended', 'prettier'],
|
||||||
plugins: ['svelte3'],
|
|
||||||
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
|
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
sourceType: 'module',
|
sourceType: 'module',
|
||||||
ecmaVersion: 2020
|
ecmaVersion: 2020,
|
||||||
|
extraFileExtensions: ['.svelte']
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
engine-strict=true
|
engine-strict=true
|
||||||
|
resolution-mode=highest
|
||||||
|
|||||||
@@ -1,18 +1,12 @@
|
|||||||
# create-svelte
|
# SvelteKit Demo app
|
||||||
|
|
||||||
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
|
The official demo app for SvelteKit, hosted on Vercel.
|
||||||
|
|
||||||
## Creating a project
|
## Deploy Your Own
|
||||||
|
|
||||||
If you're seeing this, you've probably already done this step. Congrats!
|
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fvercel%2Ftree%2Fmain%2Fexamples%2Fsveltekit-1&project-name=sveltekit-vercel&repository-name=sveltekit-vercel&demo-title=SvelteKit%20%2B%20Vercel&demo-url=https%3A%2F%2Fsveltekit-template.vercel.app%2F)
|
||||||
|
|
||||||
```bash
|
_Live Example: https://sveltekit-template.vercel.app_
|
||||||
# create a new project in the current directory
|
|
||||||
npm create svelte@latest
|
|
||||||
|
|
||||||
# create a new project in my-app
|
|
||||||
npm create svelte@latest my-app
|
|
||||||
```
|
|
||||||
|
|
||||||
## Developing
|
## Developing
|
||||||
|
|
||||||
@@ -35,4 +29,8 @@ npm run build
|
|||||||
|
|
||||||
You can preview the production build with `npm run preview`.
|
You can preview the production build with `npm run preview`.
|
||||||
|
|
||||||
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
|
## Speed Insights
|
||||||
|
|
||||||
|
Once deployed on Vercel, you can benefit from [Speed Insights](https://vercel.com/docs/concepts/speed-insights) simply by navigating to Vercel's dashboard, clicking on the 'Speed Insights' tab, and enabling the product.
|
||||||
|
|
||||||
|
You will get data once your application will be re-deployed and will receive visitors.
|
||||||
|
|||||||
@@ -16,19 +16,20 @@
|
|||||||
"@fontsource/fira-mono": "^4.5.10",
|
"@fontsource/fira-mono": "^4.5.10",
|
||||||
"@neoconfetti/svelte": "^1.0.0",
|
"@neoconfetti/svelte": "^1.0.0",
|
||||||
"@playwright/test": "^1.28.1",
|
"@playwright/test": "^1.28.1",
|
||||||
"@sveltejs/adapter-vercel": "^1.0.0",
|
"@sveltejs/adapter-vercel": "^3.0.0",
|
||||||
"@sveltejs/kit": "^1.0.0",
|
"@sveltejs/kit": "^1.5.0",
|
||||||
"@types/cookie": "^0.5.1",
|
"@types/cookie": "^0.5.1",
|
||||||
"eslint": "^8.28.0",
|
"eslint": "^8.28.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-svelte3": "^4.0.0",
|
"eslint-plugin-svelte": "^2.26.0",
|
||||||
"prettier": "^2.8.0",
|
"prettier": "^2.8.0",
|
||||||
"prettier-plugin-svelte": "^2.8.1",
|
"prettier-plugin-svelte": "^2.8.1",
|
||||||
"svelte": "^3.54.0",
|
"svelte": "^3.54.0",
|
||||||
"svelte-check": "^2.9.2",
|
"svelte-check": "^3.0.1",
|
||||||
"typescript": "^4.9.3",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^4.0.0",
|
"vite": "^4.3.0",
|
||||||
"vitest": "^0.25.3"
|
"vitest": "^0.25.3",
|
||||||
|
"web-vitals": "^3.3.1"
|
||||||
},
|
},
|
||||||
"type": "module"
|
"type": "module"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ const config = {
|
|||||||
command: 'npm run build && npm run preview',
|
command: 'npm run build && npm run preview',
|
||||||
port: 4173
|
port: 4173
|
||||||
},
|
},
|
||||||
testDir: 'tests'
|
testDir: 'tests',
|
||||||
|
testMatch: /(.+\.)?(test|spec)\.[jt]s/
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|||||||
786
examples/sveltekit-1/pnpm-lock.yaml
generated
786
examples/sveltekit-1/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
7
examples/sveltekit-1/src/app.d.ts
vendored
7
examples/sveltekit-1/src/app.d.ts
vendored
@@ -1,9 +1,12 @@
|
|||||||
// See https://kit.svelte.dev/docs/types#app
|
// See https://kit.svelte.dev/docs/types#app
|
||||||
// for information about these interfaces
|
// for information about these interfaces
|
||||||
// and what to do when importing types
|
declare global {
|
||||||
declare namespace App {
|
namespace App {
|
||||||
// interface Error {}
|
// interface Error {}
|
||||||
// interface Locals {}
|
// interface Locals {}
|
||||||
// interface PageData {}
|
// interface PageData {}
|
||||||
// interface Platform {}
|
// interface Platform {}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {};
|
||||||
|
|||||||
63
examples/sveltekit-1/src/lib/vitals.js
Normal file
63
examples/sveltekit-1/src/lib/vitals.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import { onCLS, onFCP, onFID, onLCP, onTTFB } from 'web-vitals';
|
||||||
|
|
||||||
|
const vitalsUrl = 'https://vitals.vercel-analytics.com/v1/vitals';
|
||||||
|
|
||||||
|
function getConnectionSpeed() {
|
||||||
|
// @ts-ignore
|
||||||
|
return navigator?.connection?.effectiveType ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import("web-vitals").Metric} metric
|
||||||
|
* @param {{ params: { [s: string]: any; } | ArrayLike<any>; path: string; analyticsId: string; debug: boolean; }} options
|
||||||
|
*/
|
||||||
|
function sendToAnalytics(metric, options) {
|
||||||
|
const page = Object.entries(options.params).reduce(
|
||||||
|
(acc, [key, value]) => acc.replace(value, `[${key}]`),
|
||||||
|
options.path
|
||||||
|
);
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
dsn: options.analyticsId,
|
||||||
|
id: metric.id,
|
||||||
|
page,
|
||||||
|
href: location.href,
|
||||||
|
event_name: metric.name,
|
||||||
|
value: metric.value.toString(),
|
||||||
|
speed: getConnectionSpeed()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.debug) {
|
||||||
|
console.log('[Web Vitals]', metric.name, JSON.stringify(body, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = new Blob([new URLSearchParams(body).toString()], {
|
||||||
|
// This content type is necessary for `sendBeacon`
|
||||||
|
type: 'application/x-www-form-urlencoded'
|
||||||
|
});
|
||||||
|
if (navigator.sendBeacon) {
|
||||||
|
navigator.sendBeacon(vitalsUrl, blob);
|
||||||
|
} else
|
||||||
|
fetch(vitalsUrl, {
|
||||||
|
body: blob,
|
||||||
|
method: 'POST',
|
||||||
|
credentials: 'omit',
|
||||||
|
keepalive: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any} options
|
||||||
|
*/
|
||||||
|
export function webVitals(options) {
|
||||||
|
try {
|
||||||
|
console.log(`[Web Vitals] for page ${options.path}`);
|
||||||
|
onFID((metric) => sendToAnalytics(metric, options));
|
||||||
|
onTTFB((metric) => sendToAnalytics(metric, options));
|
||||||
|
onLCP((metric) => sendToAnalytics(metric, options));
|
||||||
|
onCLS((metric) => sendToAnalytics(metric, options));
|
||||||
|
onFCP((metric) => sendToAnalytics(metric, options));
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`[Web Vitals] for page ${options.path}`, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
6
examples/sveltekit-1/src/routes/+layout.server.js
Normal file
6
examples/sveltekit-1/src/routes/+layout.server.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { env } from '$env/dynamic/private';
|
||||||
|
|
||||||
|
/** @type {import('./$types').LayoutServerLoad} */
|
||||||
|
export function load() {
|
||||||
|
return { analyticsId: env.VERCEL_ANALYTICS_ID };
|
||||||
|
}
|
||||||
@@ -1,6 +1,20 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import { browser } from '$app/environment';
|
||||||
|
import { page } from '$app/stores';
|
||||||
|
import { webVitals } from '$lib/vitals';
|
||||||
import Header from './Header.svelte';
|
import Header from './Header.svelte';
|
||||||
import './styles.css';
|
import './styles.css';
|
||||||
|
|
||||||
|
/** @type {import('./$types').LayoutServerData} */
|
||||||
|
export let data;
|
||||||
|
|
||||||
|
$: if (browser && data?.analyticsId) {
|
||||||
|
webVitals({
|
||||||
|
path: $page.url.pathname,
|
||||||
|
params: $page.params,
|
||||||
|
analyticsId: data.analyticsId
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="app">
|
<div class="app">
|
||||||
|
|||||||
@@ -107,11 +107,11 @@
|
|||||||
<a class="how-to-play" href="/sverdle/how-to-play">How to play</a>
|
<a class="how-to-play" href="/sverdle/how-to-play">How to play</a>
|
||||||
|
|
||||||
<div class="grid" class:playing={!won} class:bad-guess={form?.badGuess}>
|
<div class="grid" class:playing={!won} class:bad-guess={form?.badGuess}>
|
||||||
{#each Array(6) as _, row}
|
{#each Array.from(Array(6).keys()) as row (row)}
|
||||||
{@const current = row === i}
|
{@const current = row === i}
|
||||||
<h2 class="visually-hidden">Row {row + 1}</h2>
|
<h2 class="visually-hidden">Row {row + 1}</h2>
|
||||||
<div class="row" class:current>
|
<div class="row" class:current>
|
||||||
{#each Array(5) as _, column}
|
{#each Array.from(Array(5).keys()) as column (column)}
|
||||||
{@const answer = data.answers[row]?.[column]}
|
{@const answer = data.answers[row]?.[column]}
|
||||||
{@const value = data.guesses[row]?.[column] ?? ''}
|
{@const value = data.guesses[row]?.[column] ?? ''}
|
||||||
{@const selected = current && column === data.guesses[row].length}
|
{@const selected = current && column === data.guesses[row].length}
|
||||||
|
|||||||
@@ -2,5 +2,5 @@ import { expect, test } from '@playwright/test';
|
|||||||
|
|
||||||
test('about page has expected h1', async ({ page }) => {
|
test('about page has expected h1', async ({ page }) => {
|
||||||
await page.goto('/about');
|
await page.goto('/about');
|
||||||
expect(await page.textContent('h1')).toBe('About this app');
|
await expect(page.getByRole('heading', { name: 'About this app' })).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { sveltekit } from '@sveltejs/kit/vite';
|
import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
|
import { defineConfig } from 'vitest/config';
|
||||||
|
|
||||||
/** @type {import('vite').UserConfig} */
|
export default defineConfig({
|
||||||
const config = {
|
|
||||||
plugins: [sveltekit()],
|
plugins: [sveltekit()],
|
||||||
test: {
|
test: {
|
||||||
include: ['src/**/*.{test,spec}.{js,ts}']
|
include: ['src/**/*.{test,spec}.{js,ts}']
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
export default config;
|
|
||||||
|
|||||||
Reference in New Issue
Block a user