Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/floppy-flies-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'sv': patch
---

feat(devtools-json): default to handle replying 404 to chromium devtools
34 changes: 15 additions & 19 deletions documentation/docs/30-add-ons/03-devtools-json.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,28 @@
title: devtools-json
---

The `devtools-json` add-on installs [`vite-plugin-devtools-json`](https://github.com/ChromeDevTools/vite-plugin-devtools-json/), which is a Vite plugin for generating a Chromium DevTools project settings file on-the-fly in the development server. This file is served from `/.well-known/appspecific/com.chrome.devtools.json` and tells Chromium browsers where your project's source code lives so that you can use [the workspaces feature](https://developer.chrome.com/docs/devtools/workspaces) to edit source files in the browser.

> [!NOTE]
> Installing the plugin enables the feature for all users connecting to the dev server with a Chromium browser, and allows the browser to read and write all files within the directory. If you are using Chrome's AI Assistance feature, this may also result in data being sent to Google.
The `devtools-json` add-on adds a [`handle`](https://svelte.dev/docs/kit/hooks#Server-hooks-handle) hook that responds to the `/.well-known/appspecific/com.chrome.devtools.json` request with a 404 (aka `"Go away, Chrome DevTools!"`) during development, preventing the notice in your server logs.

## Alternatives

If you'd prefer not to install the plugin, but still want to avoid seeing a message about the missing file, you have a couple of options.
If you'd prefer to disable the feature in your browser instead, you can do this in Chrome by visiting `chrome://flags` and disabling the "DevTools Project Settings". You may also be interested in disabling "DevTools Automatic Workspace Folders" since it's closely related.

Firstly, you can prevent the request from being issued on your machine by disabling the feature in your browser. You can do this in Chrome by visiting `chrome://flags` and disabling the "DevTools Project Settings". You may also be interested in disabling "DevTools Automatic Workspace Folders" since it’s closely related.

You can also prevent the web server from issuing a notice regarding the incoming request for all developers of your application by handling the request yourself. For example, you can create a file named `.well-known/appspecific/com.chrome.devtools.json` with the contents `"Go away, Chrome DevTools!"` or you can add logic to respond to the request in your [`handle`](https://svelte.dev/docs/kit/hooks#Server-hooks-handle) hook:
If you want to enable [the workspaces feature](https://developer.chrome.com/docs/devtools/workspaces) instead, you can install [`vite-plugin-devtools-json`](https://github.com/ChromeDevTools/vite-plugin-devtools-json/), which is a Vite plugin for generating the project settings file on-the-fly in the development server:

```js
/// file: src/hooks.server.js
import { dev } from '$app/environment';

export function handle({ event, resolve }) {
if (dev && event.url.pathname === '/.well-known/appspecific/com.chrome.devtools.json') {
return new Response(undefined, { status: 404 });
}

return resolve(event);
}
/// file: vite.config.js
import devtoolsJson from 'vite-plugin-devtools-json';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';

export default defineConfig({
plugins: [sveltekit(), devtoolsJson()]
});
```

> [!NOTE]
> Installing the plugin enables the feature for all users connecting to the dev server with a Chromium browser, and allows the browser to read and write all files within the directory. If you are using Chrome's AI Assistance feature, this may also result in data being sent to Google.

## Usage

```sh
Expand All @@ -36,4 +32,4 @@ npx sv add devtools-json

## What you get

- `vite-plugin-devtools-json` added to your Vite plugin options
- A `handleDevtoolsJson` handle function added to your `hooks.server` file
1 change: 1 addition & 0 deletions packages/sv-utils/src/tooling/js/kit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ export function addHooksHandle(
} else {
node.body.push(newHandleDecl, exportDecl);
}
return;
}
// At this point, the existing `handle` doesn't call `sequence`, so we'll need to rename the original
// `handle` and create a new `handle` that uses `sequence`
Expand Down
30 changes: 19 additions & 11 deletions packages/sv/src/addons/devtools-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,28 @@ import { defineAddon } from '../core/config.ts';

export default defineAddon({
id: 'devtools-json',
shortDescription: 'devtools json',
homepage: 'https://github.com/ChromeDevTools/vite-plugin-devtools-json',
shortDescription: 'handle devtools json in dev mode',
options: {},

run: ({ sv, file }) => {
sv.devDependency('vite-plugin-devtools-json', '^1.0.0');

// add the vite plugin
run: ({ sv, language }) => {
sv.file(
file.viteConfig,
transforms.script(({ ast, js }) => {
const vitePluginName = 'devtoolsJson';
js.imports.addDefault(ast, { as: vitePluginName, from: 'vite-plugin-devtools-json' });
js.vite.addPlugin(ast, { code: `${vitePluginName}()` });
`src/hooks.server.${language}`,
transforms.script(({ ast, comments, js }) => {
js.imports.addNamed(ast, { imports: ['dev'], from: '$app/environment' });

const handleContent = `({ event, resolve }) => {
if (dev && event.url.pathname === '/.well-known/appspecific/com.chrome.devtools.json') {
return new Response(undefined, { status: 404 });
}
return resolve(event);
};`;

js.kit.addHooksHandle(ast, {
language,
newHandleName: 'handleDevtoolsJson',
handleContent,
comments
});
})
);
}
Expand Down
13 changes: 5 additions & 8 deletions packages/sv/src/addons/tests/devtools-json/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,10 @@ test.concurrent.for(testCases)('devtools-json $variant', (testCase, ctx) => {
const cwd = ctx.cwd(testCase);

const language = testCase.variant.includes('ts') ? 'ts' : 'js';
const viteFile = path.resolve(cwd, `vite.config.${language}`);
const viteContent = fs.readFileSync(viteFile, 'utf8');
const hooksFile = path.resolve(cwd, `src/hooks.server.${language}`);
const hooksContent = fs.readFileSync(hooksFile, 'utf8');

// Check if we have the import part
expect(viteContent).toContain(`import devtoolsJson from`);
expect(viteContent).toContain(`vite-plugin-devtools-json`);

// Check if it's called
expect(viteContent).toContain(`devtoolsJson()`);
expect(hooksContent).toContain(`handleDevtoolsJson`);
expect(hooksContent).toContain(`com.chrome.devtools.json`);
expect(hooksContent).toContain(`from '$app/environment'`);
});
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
"typescript": "^5.9.3",
"typescript-eslint": "^8.57.0",
"vite": "^7.3.1",
"vite-plugin-devtools-json": "^1.0.0",
"vitest": "^4.1.0",
"vitest-browser-svelte": "^2.0.2"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { sequence } from '@sveltejs/kit/hooks';
import { building } from '$app/environment';
import { auth } from '$lib/server/auth';
import { svelteKitHandler } from 'better-auth/svelte-kit';
import type { Handle } from '@sveltejs/kit';
import { sequence } from '@sveltejs/kit/hooks';
import { getTextDirection } from '$lib/paraglide/runtime';
import { paraglideMiddleware } from '$lib/paraglide/server';
import type { Handle } from '@sveltejs/kit';
import { dev, building } from '$app/environment';

const handleDevtoolsJson: Handle = ({ event, resolve }) => {
if (dev && event.url.pathname === '/.well-known/appspecific/com.chrome.devtools.json') {
return new Response(undefined, { status: 404 });
}

return resolve(event);
};

const handleParaglide: Handle = ({ event, resolve }) => paraglideMiddleware(event.request, ({ request, locale }) => {
event.request = request;
Expand All @@ -25,4 +33,4 @@ const handleBetterAuth: Handle = async ({ event, resolve }) => {
return svelteKitHandler({ event, resolve, auth, building });
};

export const handle: Handle = sequence(handleParaglide, handleBetterAuth);
export const handle: Handle = sequence(handleDevtoolsJson, handleParaglide, handleBetterAuth);
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { paraglideVitePlugin } from '@inlang/paraglide-js';
import devtoolsJson from 'vite-plugin-devtools-json';
import tailwindcss from '@tailwindcss/vite';
import { defineConfig } from 'vitest/config';
import { playwright } from '@vitest/browser-playwright';
Expand All @@ -9,7 +8,6 @@ export default defineConfig({
plugins: [
tailwindcss(),
sveltekit(),
devtoolsJson(),
paraglideVitePlugin({ project: './project.inlang', outdir: './src/lib/paraglide' })
],
test: {
Expand Down
Loading