Update package dependencies and remove unused files from node_modules

This commit is contained in:
becarta
2025-05-16 00:25:30 +02:00
parent 04584e9c98
commit 969d9c0af3
250 changed files with 47796 additions and 47121 deletions

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2021 [these people](https://github.com/sveltejs/vite-plugin-svelte/graphs/contributors)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,26 +0,0 @@
# @sveltejs/vite-plugin-svelte-inspector
A [Svelte](https://svelte.dev) inspector plugin for [Vite](https://vitejs.dev).
## Usage
```js
// vite.config.js
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import { svelteInspector } from '@sveltejs/vite-plugin-svelte-inspector';
export default defineConfig({
plugins: [
// the svelte plugin is required to work
svelte(),
svelteInspector({
/* plugin options */
})
]
});
```
## License
[MIT](./LICENSE)

View File

@@ -1,56 +0,0 @@
{
"name": "@sveltejs/vite-plugin-svelte-inspector",
"version": "4.0.1",
"license": "MIT",
"author": "dominikg",
"files": [
"src",
"types"
],
"type": "module",
"types": "types/index.d.ts",
"exports": {
".": {
"import": {
"types": "./types/index.d.ts",
"default": "./src/index.js"
}
}
},
"engines": {
"node": "^18.0.0 || ^20.0.0 || >=22"
},
"repository": {
"type": "git",
"url": "git+https://github.com/sveltejs/vite-plugin-svelte.git",
"directory": "packages/vite-plugin-svelte-inspector"
},
"keywords": [
"vite-plugin",
"vite plugin",
"vite",
"svelte"
],
"bugs": {
"url": "https://github.com/sveltejs/vite-plugin-svelte/issues"
},
"homepage": "https://github.com/sveltejs/vite-plugin-svelte#readme",
"dependencies": {
"debug": "^4.3.7"
},
"peerDependencies": {
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"svelte": "^5.0.0",
"vite": "^6.0.0"
},
"devDependencies": {
"@types/debug": "^4.1.12",
"svelte": "^5.2.7",
"vite": "^6.0.0"
},
"scripts": {
"check:publint": "publint --strict",
"check:types": "tsc --noEmit",
"generate:types": "dts-buddy -m \"@sveltejs/vite-plugin-svelte-inspector:src/public.d.ts\""
}
}

View File

@@ -1,3 +0,0 @@
import _debug from 'debug';
export const debug = _debug('vite-plugin-svelte-inspector');

View File

@@ -1,112 +0,0 @@
import { normalizePath } from 'vite';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { debug } from './debug.js';
import { defaultInspectorOptions, parseEnvironmentOptions } from './options.js';
import { cleanUrl } from './utils.js';
function getInspectorPath() {
const pluginPath = normalizePath(path.dirname(fileURLToPath(import.meta.url)));
return pluginPath.replace(
/\/vite-plugin-svelte-inspector\/src$/,
'/vite-plugin-svelte-inspector/src/runtime/'
);
}
/**
* @param {Partial<import('./public.d.ts').Options>} [options]
* @returns {import('vite').Plugin}
*/
export function svelteInspector(options) {
const inspectorPath = getInspectorPath();
debug(`svelte inspector path: ${inspectorPath}`);
/** @type {import('vite').ResolvedConfig} */
let viteConfig;
/** @type {import('./public.d.ts').Options} */
let inspectorOptions;
let disabled = false;
return {
name: 'vite-plugin-svelte-inspector',
apply: 'serve',
enforce: 'pre',
configResolved(config) {
viteConfig = config;
const environmentOptions = parseEnvironmentOptions(config);
if (environmentOptions === false) {
debug('environment options set to false, inspector disabled');
disabled = true;
return;
}
// Handle config from svelte.config.js through vite-plugin-svelte
const vps = config.plugins.find((p) => p.name === 'vite-plugin-svelte');
const configFileOptions = vps?.api?.options?.inspector;
// vite-plugin-svelte can only pass options through it's `api` instead of `options`.
// that means this plugin could be created but should be disabled, so we check this case here.
if (vps && !options && !configFileOptions && !environmentOptions) {
debug("vite-plugin-svelte didn't pass options, inspector disabled");
disabled = true;
return;
}
if (environmentOptions === true) {
inspectorOptions = defaultInspectorOptions;
} else {
inspectorOptions = {
...defaultInspectorOptions,
...configFileOptions,
...options,
...(environmentOptions || {})
};
}
inspectorOptions.__internal = {
base: config.base?.replace(/\/$/, '') || ''
};
},
async resolveId(importee, _, options) {
if (options?.ssr || disabled) {
return;
}
if (importee.startsWith('virtual:svelte-inspector-options')) {
return importee;
} else if (importee.startsWith('virtual:svelte-inspector-path:')) {
return importee.replace('virtual:svelte-inspector-path:', inspectorPath);
}
},
async load(id, options) {
if (options?.ssr || disabled) {
return;
}
if (id === 'virtual:svelte-inspector-options') {
return `export default ${JSON.stringify(inspectorOptions ?? {})}`;
} else if (id.startsWith(inspectorPath)) {
// read file ourselves to avoid getting shut out by vites fs.allow check
const file = cleanUrl(id);
if (fs.existsSync(id)) {
return await fs.promises.readFile(file, 'utf-8');
} else {
viteConfig.logger.error(
`[vite-plugin-svelte-inspector] failed to find svelte-inspector: ${id}`
);
}
}
},
transform(code, id, options) {
if (options?.ssr || disabled) {
return;
}
if (id.includes('vite/dist/client/client.mjs')) {
return { code: `${code}\nimport('virtual:svelte-inspector-path:load-inspector.js')` };
}
}
};
}

View File

@@ -1,63 +0,0 @@
import process from 'node:process';
import { loadEnv } from 'vite';
import { debug } from './debug.js';
/** @type {import('./public.d.ts').Options} */
export const defaultInspectorOptions = {
toggleKeyCombo: 'alt-x',
navKeys: { parent: 'ArrowUp', child: 'ArrowDown', next: 'ArrowRight', prev: 'ArrowLeft' },
escapeKeys: ['Backspace', 'Escape'],
openKey: 'Enter',
holdMode: true,
showToggleButton: 'active',
toggleButtonPos: 'top-right',
customStyles: true
};
/**
* @param {import('vite').ResolvedConfig} config
* @returns {Partial<import('./public.d.ts').Options> | boolean | void}
*/
export function parseEnvironmentOptions(config) {
const env = loadEnv(config.mode, config.envDir ?? process.cwd(), 'SVELTE_INSPECTOR');
const options = env?.SVELTE_INSPECTOR_OPTIONS;
const toggle = env?.SVELTE_INSPECTOR_TOGGLE;
if (options) {
try {
const parsed = JSON.parse(options);
const parsedType = typeof parsed;
if (parsedType === 'boolean') {
return parsed;
} else if (parsedType === 'object') {
if (Array.isArray(parsed)) {
throw new Error('invalid type, expected object map but got array');
}
const parsedKeys = Object.keys(parsed);
const defaultKeys = Object.keys(defaultInspectorOptions);
const unknownKeys = parsedKeys.filter((k) => !defaultKeys.includes(k));
if (unknownKeys.length) {
config.logger.warn(
`[vite-plugin-svelte-inspector] ignoring unknown options in environment SVELTE_INSPECTOR_OPTIONS: ${unknownKeys.join(
', '
)}`
);
for (const key of unknownKeys) {
delete parsed[key];
}
}
debug('loaded environment config', parsed);
return parsed;
}
} catch (e) {
config.logger.error(
`[vite-plugin-svelte-inspector] failed to parse inspector options from environment SVELTE_INSPECTOR_OPTIONS="${options}"\n${e}`
);
}
} else if (toggle) {
const keyConfig = {
toggleKeyCombo: toggle
};
debug('loaded environment config', keyConfig);
return keyConfig;
}
}

View File

@@ -1,78 +0,0 @@
export interface Options {
/**
* define a key combo to toggle inspector,
* @default 'meta-shift' on mac, 'control-shift' on other os
*
* any number of modifiers `control` `shift` `alt` `meta` followed by zero or one regular key, separated by -
* examples: control-shift, control-o, control-alt-s meta-x control-meta
* Some keys have native behavior (e.g. alt-s opens history menu on firefox).
* To avoid conflicts or accidentally typing into inputs, modifier only combinations are recommended.
*/
toggleKeyCombo?: string;
/**
* define keys to select elements with via keyboard
* @default {parent: 'ArrowUp', child: 'ArrowDown', next: 'ArrowRight', prev: 'ArrowLeft' }
*
* improves accessibility and also helps when you want to select elements that do not have a hoverable surface area
* due to tight wrapping
*
* A note for users of screen-readers:
* If you are using arrow keys to navigate the page itself, change the navKeys to avoid conflicts.
* e.g. navKeys: {parent: 'w', prev: 'a', child: 's', next: 'd'}
*
*
* parent: select closest parent
* child: select first child (or grandchild)
* next: next sibling (or parent if no next sibling exists)
* prev: previous sibling (or parent if no prev sibling exists)
*/
navKeys?: { parent: string; child: string; next: string; prev: string };
/**
* define key to open the editor for the currently selected dom node
*
* @default 'Enter'
*/
openKey?: string;
/**
* define keys to close the inspector
* @default ['Backspace', 'Escape']
*/
escapeKeys?: string[];
/**
* inspector is automatically disabled when releasing toggleKeyCombo after holding it for a longpress
* @default true
*/
holdMode?: boolean;
/**
* when to show the toggle button
* @default 'active'
*/
showToggleButton?: 'always' | 'active' | 'never';
/**
* where to display the toggle button
* @default top-right
*/
toggleButtonPos?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
/**
* inject custom styles when inspector is active
*/
customStyles?: boolean;
/**
* internal options that are automatically set, not to be set or used by users
* @internal
*/
__internal?: {
// vite base url
base: string;
};
}
// eslint-disable-next-line n/no-missing-import
export * from './index.js';

View File

@@ -1,411 +0,0 @@
<svelte:options runes={true} />
<script>
// do not use TS here so that this component works in non-ts projects too
import { onMount } from 'svelte';
import options from 'virtual:svelte-inspector-options';
const toggle_combo = options.toggleKeyCombo?.toLowerCase().split('-');
const escape_keys = options.escapeKeys?.map((k) => k.toLowerCase());
const nav_keys = Object.values(options.navKeys).map((k) => k?.toLowerCase());
const open_key = options.openKey?.toLowerCase();
let enabled = $state(false);
let has_opened = $state(false);
const icon = `data:image/svg+xml;base64,${btoa(
`
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="25" viewBox="0 0 107 128">
<title>svelte-inspector-logo</title>
<path d="M94.1566,22.8189c-10.4-14.8851-30.94-19.2971-45.7914-9.8348L22.2825,29.6078A29.9234,29.9234,0,0,0,8.7639,49.6506a31.5136,31.5136,0,0,0,3.1076,20.2318A30.0061,30.0061,0,0,0,7.3953,81.0653a31.8886,31.8886,0,0,0,5.4473,24.1157c10.4022,14.8865,30.9423,19.2966,45.7914,9.8348L84.7167,98.3921A29.9177,29.9177,0,0,0,98.2353,78.3493,31.5263,31.5263,0,0,0,95.13,58.117a30,30,0,0,0,4.4743-11.1824,31.88,31.88,0,0,0-5.4473-24.1157" style="fill:#ff3e00"/><path d="M45.8171,106.5815A20.7182,20.7182,0,0,1,23.58,98.3389a19.1739,19.1739,0,0,1-3.2766-14.5025,18.1886,18.1886,0,0,1,.6233-2.4357l.4912-1.4978,1.3363.9815a33.6443,33.6443,0,0,0,10.203,5.0978l.9694.2941-.0893.9675a5.8474,5.8474,0,0,0,1.052,3.8781,6.2389,6.2389,0,0,0,6.6952,2.485,5.7449,5.7449,0,0,0,1.6021-.7041L69.27,76.281a5.4306,5.4306,0,0,0,2.4506-3.631,5.7948,5.7948,0,0,0-.9875-4.3712,6.2436,6.2436,0,0,0-6.6978-2.4864,5.7427,5.7427,0,0,0-1.6.7036l-9.9532,6.3449a19.0329,19.0329,0,0,1-5.2965,2.3259,20.7181,20.7181,0,0,1-22.2368-8.2427,19.1725,19.1725,0,0,1-3.2766-14.5024,17.9885,17.9885,0,0,1,8.13-12.0513L55.8833,23.7472a19.0038,19.0038,0,0,1,5.3-2.3287A20.7182,20.7182,0,0,1,83.42,29.6611a19.1739,19.1739,0,0,1,3.2766,14.5025,18.4,18.4,0,0,1-.6233,2.4357l-.4912,1.4978-1.3356-.98a33.6175,33.6175,0,0,0-10.2037-5.1l-.9694-.2942.0893-.9675a5.8588,5.8588,0,0,0-1.052-3.878,6.2389,6.2389,0,0,0-6.6952-2.485,5.7449,5.7449,0,0,0-1.6021.7041L37.73,51.719a5.4218,5.4218,0,0,0-2.4487,3.63,5.7862,5.7862,0,0,0,.9856,4.3717,6.2437,6.2437,0,0,0,6.6978,2.4864,5.7652,5.7652,0,0,0,1.602-.7041l9.9519-6.3425a18.978,18.978,0,0,1,5.2959-2.3278,20.7181,20.7181,0,0,1,22.2368,8.2427,19.1725,19.1725,0,0,1,3.2766,14.5024,17.9977,17.9977,0,0,1-8.13,12.0532L51.1167,104.2528a19.0038,19.0038,0,0,1-5.3,2.3287" style="fill:#fff"/>
<polygon points="0,0 15,40 40,20" stroke="#ff3e00" fill="#ff3e00"></polygon>
</svg>
`
.replace(/[\n\r\t\s]+/g, ' ')
.trim()
)}`;
// location of code in file
let file_loc = $state();
// cursor pos and width for file_loc overlay positioning
let x = $state(),
y = $state(),
w = $state();
let active_el = $state();
let hold_start_ts = $state();
let show_toggle = $derived(
options.showToggleButton === 'always' || (options.showToggleButton === 'active' && enabled)
);
function mousemove(e) {
x = e.x;
y = e.y;
}
function find_selectable_parent(el, include_self = false) {
if (!include_self) {
el = el.parentNode;
}
while (el) {
if (is_selectable(el)) {
return el;
}
el = el.parentNode;
}
}
function find_selectable_child(el) {
return [...el.querySelectorAll('*')].find(is_selectable);
}
function find_selectable_sibling(el, prev = false) {
do {
el = prev ? el.previousElementSibling : el.nextElementSibling;
if (is_selectable(el)) {
return el;
}
} while (el);
}
function find_selectable_for_nav(key) {
const el = active_el;
if (!el) {
return find_selectable_child(document?.body);
}
switch (key) {
case options.navKeys.parent:
return find_selectable_parent(el);
case options.navKeys.child:
return find_selectable_child(el);
case options.navKeys.next:
return find_selectable_sibling(el) || find_selectable_parent(el);
case options.navKeys.prev:
return find_selectable_sibling(el, true) || find_selectable_parent(el);
default:
return;
}
}
function is_selectable(el) {
const file = el?.__svelte_meta?.loc?.file;
if (!file || file.includes('node_modules/')) {
return false; // no file or 3rd party
}
const id = el.getAttribute('id');
if (id === 'svelte-announcer' || id?.startsWith('svelte-inspector-')) {
return false; // ignore some elements by id that would be selectable from keyboard nav otherwise
}
return true;
}
function mouseover({ target }) {
const el = find_selectable_parent(target, true);
activate(el, false);
}
function activate(el, set_bubble_pos = true) {
if (options.customStyles && el !== active_el) {
if (active_el) {
active_el.classList.remove('svelte-inspector-active-target');
}
if (el) {
el.classList.add('svelte-inspector-active-target');
}
}
if (el) {
const { file, line, column } = el.__svelte_meta.loc;
file_loc = `${file}:${line + 1}:${column + 1}`;
} else {
file_loc = null;
}
active_el = el;
if (set_bubble_pos) {
const pos = el.getBoundingClientRect();
x = Math.ceil(pos.left);
y = Math.ceil(pos.bottom - 20);
}
}
function open_editor(e) {
if (file_loc) {
stop(e);
fetch(`${options.__internal.base}/__open-in-editor?file=${encodeURIComponent(file_loc)}`);
has_opened = true;
if (options.holdMode && is_holding()) {
disable();
}
}
}
function is_active(key, e) {
switch (key) {
case 'shift':
case 'control':
case 'alt':
case 'meta':
return e.getModifierState(key.charAt(0).toUpperCase() + key.slice(1));
default:
return key === e.code.replace(/^Key/, '').toLowerCase() || key === e.key.toLowerCase();
}
}
function is_combo(e) {
return toggle_combo?.every((k) => is_active(k, e));
}
function is_escape(e) {
return escape_keys?.some((k) => is_active(k, e));
}
function is_toggle(e) {
return toggle_combo?.some((k) => is_active(k, e));
}
function is_nav(e) {
return nav_keys?.some((k) => is_active(k, e));
}
function is_open(e) {
return open_key && is_active(open_key, e);
}
function is_holding() {
return hold_start_ts && Date.now() - hold_start_ts > 250;
}
function stop(e) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
}
function keydown(e) {
if (e.repeat || e.key == null || (!enabled && !is_toggle(e))) {
return;
}
if (is_combo(e)) {
toggle();
if (options.holdMode && enabled) {
hold_start_ts = Date.now();
}
} else if (enabled) {
if (is_nav(e)) {
const el = find_selectable_for_nav(e.key);
if (el) {
activate(el);
stop(e);
}
} else if (is_open(e)) {
open_editor(e);
} else if (is_holding() || is_escape(e)) {
// is_holding() checks for unhandled additional key pressed
// while holding the toggle keys, which is possibly another
// shortcut (e.g. 'meta-shift-x'), so disable again.
disable();
}
}
}
function keyup(e) {
if (e.repeat || e.key == null || !enabled) {
return;
}
if (is_toggle(e)) {
if (is_holding()) {
disable();
} else {
hold_start_ts = null;
}
}
}
function toggle() {
if (enabled) {
disable();
} else {
enable();
}
}
function listeners(body, enabled) {
const l = enabled ? body.addEventListener : body.removeEventListener;
l('mousemove', mousemove);
l('mouseover', mouseover);
l('click', open_editor, true);
}
function enable() {
enabled = true;
const b = document.body;
if (options.customStyles) {
b.classList.add('svelte-inspector-enabled');
}
listeners(b, enabled);
activate_initial_el();
}
function activate_initial_el() {
const hov = innermost_hover_el();
let el = find_selectable_parent(hov, true);
if (!el) {
const act = document.activeElement;
el = find_selectable_parent(act, true);
}
if (!el) {
el = find_selectable_child(document.body);
}
if (el) {
activate(el);
}
}
function innermost_hover_el() {
let e = document.body.querySelector(':hover');
let result;
while (e) {
result = e;
e = e.querySelector(':hover');
}
return result;
}
function disable() {
enabled = false;
has_opened = false;
hold_start_ts = null;
const b = document.body;
listeners(b, enabled);
if (options.customStyles) {
b.classList.remove('svelte-inspector-enabled');
active_el?.classList.remove('svelte-inspector-active-target');
}
active_el = null;
}
function visibilityChange() {
if (document.visibilityState === 'hidden') {
onLeave();
}
}
function onLeave() {
// disable if a file has been opened or combo is held
if (enabled && (has_opened || hold_start_ts)) {
disable();
}
}
onMount(() => {
const s = document.createElement('style');
s.setAttribute('type', 'text/css');
s.setAttribute('id', 'svelte-inspector-style');
s.textContent = `:root { --svelte-inspector-icon: url(${icon})};`;
document.head.append(s);
if (toggle_combo) {
document.body.addEventListener('keydown', keydown);
if (options.holdMode) {
document.body.addEventListener('keyup', keyup);
}
}
document.addEventListener('visibilitychange', visibilityChange);
document.documentElement.addEventListener('mouseleave', onLeave);
return () => {
// make sure we get rid of everything
disable();
const s = document.head.querySelector('#svelte-inspector-style');
if (s) {
document.head.removeChild(s);
}
if (toggle_combo) {
document.body.removeEventListener('keydown', keydown);
if (options.holdMode) {
document.body.removeEventListener('keyup', keyup);
}
}
document.removeEventListener('visibilitychange', visibilityChange);
document.documentElement.removeEventListener('mouseleave', onLeave);
};
});
</script>
{#if show_toggle}
<button
id="svelte-inspector-toggle"
class:enabled
style={`background-image: var(--svelte-inspector-icon);${options.toggleButtonPos
.split('-')
.map((p) => `${p}: 8px;`)
.join('')}`}
onclick={() => toggle()}
aria-label={`${enabled ? 'disable' : 'enable'} svelte-inspector`}
></button>
{/if}
{#if enabled && active_el && file_loc}
{@const loc = active_el.__svelte_meta.loc}
<div
id="svelte-inspector-overlay"
style:left="{Math.min(x + 3, document.documentElement.clientWidth - w - 10)}px"
style:top="{document.documentElement.clientHeight < y + 50 ? y - 30 : y + 30}px"
bind:offsetWidth={w}
>
&lt;{active_el.tagName.toLowerCase()}&gt;&nbsp;{file_loc}
</div>
<div id="svelte-inspector-announcer" aria-live="assertive" aria-atomic="true">
{active_el.tagName.toLowerCase()} in file {loc.file} on line {loc.line} column {loc.column}
</div>
{/if}
<style>
:global(body.svelte-inspector-enabled *) {
cursor: var(--svelte-inspector-icon), crosshair !important;
}
:global(.svelte-inspector-active-target) {
outline: 2px dashed #ff3e00 !important;
}
#svelte-inspector-overlay {
position: fixed;
background-color: rgba(0, 0, 0, 0.8);
color: #fff;
padding: 2px 4px;
border-radius: 5px;
z-index: 999999;
pointer-events: none;
}
#svelte-inspector-toggle {
all: unset;
border: 1px solid #ff3e00;
border-radius: 8px;
position: fixed;
height: 32px;
width: 32px;
background-color: white;
background-position: center;
background-repeat: no-repeat;
cursor: pointer;
}
#svelte-inspector-announcer {
position: absolute;
left: 0px;
top: 0px;
clip: rect(0px, 0px, 0px, 0px);
clip-path: inset(50%);
overflow: hidden;
white-space: nowrap;
width: 1px;
height: 1px;
}
#svelte-inspector-toggle:not(.enabled) {
filter: grayscale(1);
}
#svelte-inspector-toggle:hover {
background-color: #facece;
}
</style>

View File

@@ -1,14 +0,0 @@
// eslint-disable-next-line n/no-missing-import
import Inspector from 'virtual:svelte-inspector-path:Inspector.svelte';
import { mount } from 'svelte';
function create_inspector_host() {
const id = 'svelte-inspector-host';
if (document.getElementById(id) != null) {
throw new Error('svelte-inspector-host element already exists');
}
const el = document.createElement('div');
el.setAttribute('id', id);
document.documentElement.appendChild(el);
return el;
}
mount(Inspector, { target: create_inspector_host() });

View File

@@ -1,8 +0,0 @@
const postfixRE = /[?#].*$/s;
/**
* @param {string} url
*/
export function cleanUrl(url) {
return url.replace(postfixRE, '');
}

View File

@@ -1,82 +0,0 @@
declare module '@sveltejs/vite-plugin-svelte-inspector' {
export interface Options {
/**
* define a key combo to toggle inspector,
* @default 'meta-shift' on mac, 'control-shift' on other os
*
* any number of modifiers `control` `shift` `alt` `meta` followed by zero or one regular key, separated by -
* examples: control-shift, control-o, control-alt-s meta-x control-meta
* Some keys have native behavior (e.g. alt-s opens history menu on firefox).
* To avoid conflicts or accidentally typing into inputs, modifier only combinations are recommended.
*/
toggleKeyCombo?: string;
/**
* define keys to select elements with via keyboard
* @default {parent: 'ArrowUp', child: 'ArrowDown', next: 'ArrowRight', prev: 'ArrowLeft' }
*
* improves accessibility and also helps when you want to select elements that do not have a hoverable surface area
* due to tight wrapping
*
* A note for users of screen-readers:
* If you are using arrow keys to navigate the page itself, change the navKeys to avoid conflicts.
* e.g. navKeys: {parent: 'w', prev: 'a', child: 's', next: 'd'}
*
*
* parent: select closest parent
* child: select first child (or grandchild)
* next: next sibling (or parent if no next sibling exists)
* prev: previous sibling (or parent if no prev sibling exists)
*/
navKeys?: { parent: string; child: string; next: string; prev: string };
/**
* define key to open the editor for the currently selected dom node
*
* @default 'Enter'
*/
openKey?: string;
/**
* define keys to close the inspector
* @default ['Backspace', 'Escape']
*/
escapeKeys?: string[];
/**
* inspector is automatically disabled when releasing toggleKeyCombo after holding it for a longpress
* @default true
*/
holdMode?: boolean;
/**
* when to show the toggle button
* @default 'active'
*/
showToggleButton?: 'always' | 'active' | 'never';
/**
* where to display the toggle button
* @default top-right
*/
toggleButtonPos?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
/**
* inject custom styles when inspector is active
*/
customStyles?: boolean;
/**
* internal options that are automatically set, not to be set or used by users
* */
__internal?: {
// vite base url
base: string;
};
}
export function svelteInspector(options?: Partial<Options>): import("vite").Plugin;
export {};
}
//# sourceMappingURL=index.d.ts.map

View File

@@ -1,17 +0,0 @@
{
"version": 3,
"file": "index.d.ts",
"names": [
"Options",
"svelteInspector"
],
"sources": [
"../src/public.d.ts",
"../src/index.js"
],
"sourcesContent": [
null,
null
],
"mappings": ";kBAAiBA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCoBRC,eAAeA"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@sveltejs/vite-plugin-svelte",
"version": "5.0.3",
"version": "3.1.2",
"license": "MIT",
"author": "dominikg",
"files": [
@@ -18,7 +18,7 @@
}
},
"engines": {
"node": "^18.0.0 || ^20.0.0 || >=22"
"node": "^18.0.0 || >=20"
},
"repository": {
"type": "git",
@@ -36,23 +36,24 @@
},
"homepage": "https://github.com/sveltejs/vite-plugin-svelte#readme",
"dependencies": {
"@sveltejs/vite-plugin-svelte-inspector": "^4.0.1",
"debug": "^4.4.0",
"@sveltejs/vite-plugin-svelte-inspector": "^2.1.0",
"debug": "^4.3.4",
"deepmerge": "^4.3.1",
"kleur": "^4.1.5",
"magic-string": "^0.30.15",
"vitefu": "^1.0.4"
"magic-string": "^0.30.10",
"svelte-hmr": "^0.16.0",
"vitefu": "^0.2.5"
},
"peerDependencies": {
"svelte": "^5.0.0",
"vite": "^6.0.0"
"svelte": "^4.0.0 || ^5.0.0-next.0",
"vite": "^5.0.0"
},
"devDependencies": {
"@types/debug": "^4.1.12",
"esbuild": "^0.24.0",
"sass": "^1.83.0",
"svelte": "^5.12.0",
"vite": "^6.0.3"
"esbuild": "^0.20.2",
"sass": "^1.75.0",
"svelte": "^4.2.15",
"vite": "^5.2.9"
},
"scripts": {
"check:publint": "publint --strict",

View File

@@ -81,8 +81,8 @@ export async function handleHotUpdate(compileSvelte, ctx, svelteRequest, cache,
}
/**
* @param {import('./types/compile.d.ts').Code | null} [prev]
* @param {import('./types/compile.d.ts').Code | null} [next]
* @param {import('./types/compile.d.ts').Code} [prev]
* @param {import('./types/compile.d.ts').Code} [next]
* @returns {boolean}
*/
function cssChanged(prev, next) {
@@ -90,8 +90,8 @@ function cssChanged(prev, next) {
}
/**
* @param {import('./types/compile.d.ts').Code | null} [prev]
* @param {import('./types/compile.d.ts').Code | null} [next]
* @param {import('./types/compile.d.ts').Code} [prev]
* @param {import('./types/compile.d.ts').Code} [next]
* @param {string} [filename]
* @returns {boolean}
*/

View File

@@ -1,8 +1,9 @@
import fs from 'node:fs';
import process from 'node:process';
import { svelteInspector } from '@sveltejs/vite-plugin-svelte-inspector';
import { handleHotUpdate } from './handle-hot-update.js';
import { log, logCompilerWarnings } from './utils/log.js';
import { log, logCompilerWarnings, logSvelte5Warning } from './utils/log.js';
import { createCompileSvelte } from './utils/compile.js';
import { buildIdParser, buildModuleIdParser } from './utils/id.js';
import {
@@ -10,15 +11,15 @@ import {
validateInlineOptions,
resolveOptions,
patchResolvedViteConfig,
preResolveOptions,
ensureConfigEnvironmentMainFields,
ensureConfigEnvironmentConditions
preResolveOptions
} from './utils/options.js';
import { ensureWatchedFile, setupWatchers } from './utils/watch.js';
import { toRollupError } from './utils/error.js';
import { saveSvelteMetadata } from './utils/optimizer.js';
import { VitePluginSvelteCache } from './utils/vite-plugin-svelte-cache.js';
import { loadRaw } from './utils/load-raw.js';
import { isSvelte5 } from './utils/svelte-version.js';
import * as svelteCompiler from 'svelte/compiler';
/**
@@ -42,6 +43,7 @@ export function svelte(inlineOptions) {
let viteConfig;
/** @type {import('./types/compile.d.ts').CompileSvelte} */
let compileSvelte;
/* eslint-enable no-unused-vars */
/** @type {import('./types/plugin-api.d.ts').PluginAPI} */
const api = {};
/** @type {import('vite').Plugin[]} */
@@ -66,21 +68,11 @@ export function svelte(inlineOptions) {
return extraViteConfig;
},
configEnvironment(name, config, opts) {
ensureConfigEnvironmentMainFields(name, config, opts);
// @ts-expect-error the function above should make `resolve.mainFields` non-nullable
config.resolve.mainFields.unshift('svelte');
ensureConfigEnvironmentConditions(name, config, opts);
// @ts-expect-error the function above should make `resolve.conditions` non-nullable
config.resolve.conditions.push('svelte');
},
async configResolved(config) {
options = resolveOptions(options, config, cache);
patchResolvedViteConfig(config, options);
requestParser = buildIdParser(options);
compileSvelte = createCompileSvelte();
compileSvelte = createCompileSvelte(options);
viteConfig = config;
// TODO deep clone to avoid mutability from outside?
api.options = options;
@@ -136,11 +128,7 @@ export function svelte(inlineOptions) {
const ssr = !!opts?.ssr;
const svelteRequest = requestParser(importee, ssr);
if (svelteRequest?.query.svelte) {
if (
svelteRequest.query.type === 'style' &&
!svelteRequest.raw &&
!svelteRequest.query.inline
) {
if (svelteRequest.query.type === 'style' && !svelteRequest.raw) {
// return cssId with root prefix so postcss pipeline of vite finds the directory correctly
// see https://github.com/sveltejs/vite-plugin-svelte/issues/14
log.debug(
@@ -190,7 +178,8 @@ export function svelte(inlineOptions) {
},
handleHotUpdate(ctx) {
if (!options.compilerOptions.hmr || !options.emitCss) {
// @ts-expect-error svelte4 does not have hmr option
if ((!options.hot && !options.compilerOptions.hmr) || !options.emitCss) {
return;
}
const svelteRequest = requestParser(ctx.file, false, ctx.timestamp);
@@ -201,8 +190,12 @@ export function svelte(inlineOptions) {
async buildEnd() {
await options.stats?.finishAll();
}
},
{
}
];
if (isSvelte5) {
logSvelte5Warning();
// TODO move to separate file
plugins.push({
name: 'vite-plugin-svelte-module',
enforce: 'post',
async configResolved() {
@@ -215,8 +208,8 @@ export function svelte(inlineOptions) {
return;
}
try {
const compileResult = svelteCompiler.compileModule(code, {
dev: !viteConfig.isProduction,
// @ts-expect-error compileModule does not exist in svelte4
const compileResult = await svelteCompiler.compileModule(code, {
generate: ssr ? 'server' : 'client',
filename: moduleRequest.filename
});
@@ -226,9 +219,12 @@ export function svelte(inlineOptions) {
throw toRollupError(e, options);
}
}
},
svelteInspector()
];
});
}
if (!isSvelte5) {
// TODO reenable once svelte5 has support and update utils/log.js#logSvelte5Warning
plugins.push(svelteInspector());
}
return plugins;
}

View File

@@ -1,4 +1,3 @@
import process from 'node:process';
import { isCSSRequest, preprocessCSS, resolveConfig, transformWithEsbuild } from 'vite';
import { mapToRelative, removeLangSuffix } from './utils/sourcemaps.js';
@@ -17,7 +16,7 @@ export const lang_sep = '.vite-preprocess';
export function vitePreprocess(opts) {
/** @type {import('svelte/compiler').PreprocessorGroup} */
const preprocessor = { name: 'vite-preprocess' };
if (opts?.script === true) {
if (opts?.script !== false) {
preprocessor.script = viteScript().script;
}
if (opts?.style !== false) {
@@ -99,16 +98,15 @@ async function createCssTransform(style, config) {
let resolvedConfig;
// @ts-expect-error special prop added if running in v-p-s
if (style.__resolvedConfig) {
// @ts-expect-error not typed
// @ts-expect-error
resolvedConfig = style.__resolvedConfig;
} else if (isResolvedConfig(config)) {
resolvedConfig = config;
} else {
// default to "build" if no NODE_ENV is set to avoid running in dev mode for svelte-check etc.
const useBuild = !process.env.NODE_ENV || process.env.NODE_ENV === 'production';
const command = useBuild ? 'build' : 'serve';
const defaultMode = useBuild ? 'production' : 'development';
resolvedConfig = await resolveConfig(config, command, defaultMode, defaultMode, false);
resolvedConfig = await resolveConfig(
config,
process.env.NODE_ENV === 'production' ? 'build' : 'serve'
);
}
return async (code, filename) => {
return preprocessCSS(code, filename, resolvedConfig);

View File

@@ -1,5 +1,7 @@
import type { InlineConfig, ResolvedConfig } from 'vite';
import type { CompileOptions, Warning, PreprocessorGroup } from 'svelte/compiler';
import type { CompileOptions } from 'svelte/compiler';
import type { Warning } from 'svelte/types/compiler/interfaces';
import type { PreprocessorGroup } from 'svelte/compiler';
import type { Options as InspectorOptions } from '@sveltejs/vite-plugin-svelte-inspector';
export type Options = Omit<SvelteConfig, 'vitePlugin'> & PluginOptionsInline;
@@ -15,7 +17,7 @@ interface PluginOptionsInline extends PluginOptions {
configFile?: string | false;
}
export interface PluginOptions {
interface PluginOptions {
/**
* A `picomatch` pattern, or array of patterns, which specifies the files the plugin should
* operate on. By default, all svelte files are included.
@@ -38,13 +40,27 @@ export interface PluginOptions {
emitCss?: boolean;
/**
* Enable or disable Hot Module Replacement.
* Deprecated, use compilerOptions.hmr instead!
*
* @deprecated
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
* DO NOT CUSTOMIZE SVELTE-HMR OPTIONS UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING
*
* YOU HAVE BEEN WARNED
*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
* Set an object to pass custom options to svelte-hmr
*
* @see https://github.com/rixo/svelte-hmr#options
* @default true for development, always false for production
*/
hot?: boolean;
hot?:
| boolean
| {
injectCss?: boolean;
partialAccept?: boolean;
[key: string]: any;
};
/**
* Some Vite plugins can contribute additional preprocessors by defining `api.sveltePreprocess`.
* If you don't want to use them, set this to true to ignore them all or use an array of strings
@@ -92,9 +108,9 @@ export interface PluginOptions {
* @example
* ```
* ({ filename, compileOptions }) => {
* // Dynamically set runes mode per Svelte file
* if (forceRunesMode(filename) && !compileOptions.runes) {
* return { runes: true };
* // Dynamically set hydration per Svelte file
* if (compileWithHydratable(filename) && !compileOptions.hydratable) {
* return { hydratable: true };
* }
* }
* ```
@@ -135,22 +151,8 @@ export interface SvelteConfig {
/**
* Handles warning emitted from the Svelte compiler
*
* warnings emitted for files in node_modules are logged at the debug level, to see them run
* `DEBUG=vite-plugin-svelte:node-modules-onwarn pnpm build`
*
* @example
* ```
* (warning, defaultHandler) => {
* // ignore some warnings
* if (!['foo','bar'].includes(warning.code)) {
* defaultHandler(warning);
* }
* }
* ```
*
*/
onwarn?: (warning: Warning, defaultHandler: (warning: Warning) => void) => void;
onwarn?: (warning: Warning, defaultHandler?: (warning: Warning) => void) => void;
/**
* Options for vite-plugin-svelte
*/
@@ -177,15 +179,6 @@ interface ExperimentalOptions {
}
interface CompileModuleOptions {
/**
* infix that must be present in filename
* @default ['.svelte.']
*/
infixes?: string[];
/**
* module extensions
* @default ['.ts','.js']
*/
extensions?: string[];
include?: Arrayable<string>;
exclude?: Arrayable<string>;
@@ -194,17 +187,8 @@ interface CompileModuleOptions {
type Arrayable<T> = T | T[];
export interface VitePreprocessOptions {
/**
* preprocess script block with vite pipeline.
* Since svelte5 this is not needed for typescript anymore
*
* @default false
*/
script?: boolean;
/**
* preprocess style blocks with vite pipeline
*/
style?: boolean | InlineConfig | ResolvedConfig;
}
// eslint-disable-next-line n/no-missing-import
export * from './index.js';

View File

@@ -1,4 +1,4 @@
import type { CompileOptions } from 'svelte/compiler';
import type { CompileOptions } from 'svelte/types/compiler/interfaces';
export type SvelteQueryTypes = 'style' | 'script' | 'preprocessed' | 'all';
@@ -9,13 +9,12 @@ export interface RequestQuery {
sourcemap?: boolean;
compilerOptions?: Pick<
CompileOptions,
'generate' | 'dev' | 'css' | 'customElement' | 'immutable'
'generate' | 'dev' | 'css' | 'hydratable' | 'customElement' | 'immutable' | 'enableSourcemap'
>;
// vite specific
url?: boolean;
raw?: boolean;
direct?: boolean;
inline?: boolean;
}
export interface SvelteRequest {

View File

@@ -1,14 +1,14 @@
import type { Warning } from 'svelte/compiler';
import type { Warning } from 'svelte/types/compiler/interfaces';
export interface LogFn extends SimpleLogFn {
(message: string, payload?: unknown, namespace?: string): void;
(message: string, payload?: any, namespace?: string): void;
enabled: boolean;
once: SimpleLogFn;
}
export interface SimpleLogFn {
(message: string, payload?: unknown, namespace?: string): void;
(message: string, payload?: any, namespace?: string): void;
}
export type SvelteWarningsMessage = {

View File

@@ -1,6 +1,5 @@
import type { CompileOptions } from 'svelte/compiler';
import type { CompileOptions } from 'svelte/types/compiler/interfaces';
import type { ViteDevServer } from 'vite';
// eslint-disable-next-line n/no-missing-import
import { VitePluginSvelteStats } from '../utils/vite-plugin-svelte-stats.js';
import type { Options } from '../public.d.ts';

View File

@@ -1,5 +1,6 @@
import * as svelte from 'svelte/compiler';
// @ts-ignore
import { createMakeHot } from 'svelte-hmr';
import { safeBase64Hash } from './hash.js';
import { log } from './log.js';
@@ -9,17 +10,19 @@ import {
} from './preprocess.js';
import { mapToRelative } from './sourcemaps.js';
import { enhanceCompileError } from './error.js';
import { isSvelte5 } from './svelte-version.js';
// TODO this is a patched version of https://github.com/sveltejs/vite-plugin-svelte/pull/796/files#diff-3bce0b33034aad4b35ca094893671f7e7ddf4d27254ae7b9b0f912027a001b15R10
// which is closer to the other regexes in at least not falling into commented script
// but ideally would be shared exactly with svelte and other tools that use it
const scriptLangRE =
/<!--[^]*?-->|<script\s+(?:[^>]*|(?:[^=>'"/]+=(?:"[^"]*"|'[^']*'|[^>\s]+)\s+)*)lang=(["'])?([^"' >]+)\1[^>]*>/g;
/<!--[^]*?-->|<script (?:[^>]*|(?:[^=>'"/]+=(?:"[^"]*"|'[^']*'|[^>\s]+)\s+)*)lang=["']?([^"' >]+)["']?[^>]*>/g;
/**
* @param {Function} [makeHot]
* @returns {import('../types/compile.d.ts').CompileSvelte}
*/
export function createCompileSvelte() {
export const _createCompileSvelte = (makeHot) => {
/** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection | undefined} */
let stats;
const devStylePreprocessor = createInjectScopeEverythingRulePreprocessorGroup();
@@ -29,7 +32,7 @@ export function createCompileSvelte() {
const { emitCss = true } = options;
/** @type {string[]} */
const dependencies = [];
/** @type {import('svelte/compiler').Warning[]} */
/** @type {import('svelte/types/compiler/interfaces').Warning[]} */
const warnings = [];
if (options.stats) {
@@ -60,17 +63,18 @@ export function createCompileSvelte() {
const compileOptions = {
...options.compilerOptions,
filename,
generate: ssr ? 'server' : 'client'
// @ts-expect-error svelte5 uses server/client, svelte4 uses ssr/dom
generate: isSvelte5 ? (ssr ? 'server' : 'client') : ssr ? 'ssr' : 'dom'
};
if (compileOptions.hmr && options.emitCss) {
if (options.hot && options.emitCss) {
const hash = `s-${safeBase64Hash(normalizedFilename)}`;
compileOptions.cssHash = () => hash;
}
let preprocessed;
let preprocessors = options.preprocess;
if (!options.isBuild && options.emitCss && compileOptions.hmr) {
if (!options.isBuild && options.emitCss && options.hot) {
// inject preprocessor that ensures css hmr works better
if (!Array.isArray(preprocessors)) {
preprocessors = preprocessors
@@ -128,22 +132,12 @@ export function createCompileSvelte() {
...dynamicCompileOptions
}
: compileOptions;
const endStat = stats?.start(filename);
/** @type {import('svelte/compiler').CompileResult} */
/** @type {import('svelte/types/compiler/interfaces').CompileResult} */
let compiled;
try {
compiled = svelte.compile(finalCode, { ...finalCompileOptions, filename });
// patch output with partial accept until svelte does it
// TODO remove later
if (
options.server?.config.experimental.hmrPartialAccept &&
compiled.js.code.includes('import.meta.hot.accept(')
) {
compiled.js.code = compiled.js.code.replaceAll(
'import.meta.hot.accept(',
'import.meta.hot.acceptExports(["default"],'
);
}
compiled = svelte.compile(finalCode, finalCompileOptions);
} catch (e) {
enhanceCompileError(e, code, preprocessors);
throw e;
@@ -162,18 +156,31 @@ export function createCompileSvelte() {
}
if (!raw) {
// wire css import and code for hmr
const hasCss = compiled.css?.code?.trim()?.length ?? 0 > 0;
const hasCss = compiled.css?.code?.trim().length > 0;
// compiler might not emit css with mode none or it may be empty
if (emitCss && hasCss) {
// TODO properly update sourcemap?
compiled.js.code += `\nimport ${JSON.stringify(cssId)};\n`;
}
// only apply hmr when not in ssr context and hot options are set
if (!ssr && makeHot) {
compiled.js.code = makeHot({
id: filename,
compiledCode: compiled.js.code,
//@ts-expect-error hot isn't a boolean at this point
hotOptions: { ...options.hot, injectCss: options.hot?.injectCss === true && hasCss },
compiled,
originalCode: code,
compileOptions: finalCompileOptions
});
}
}
let lang = 'js';
for (const match of code.matchAll(scriptLangRE)) {
if (match[2]) {
lang = match[2];
if (match[1]) {
lang = match[1];
break;
}
}
@@ -182,10 +189,41 @@ export function createCompileSvelte() {
filename,
normalizedFilename,
lang,
// @ts-ignore
compiled,
ssr,
dependencies,
preprocessed: preprocessed ?? { code }
};
};
};
/**
* @param {import('../types/options.d.ts').ResolvedOptions} options
* @returns {Function | undefined}
*/
function buildMakeHot(options) {
const needsMakeHot =
!isSvelte5 && options.hot !== false && options.isServe && !options.isProduction;
if (needsMakeHot) {
// @ts-ignore
const hotApi = options?.hot?.hotApi;
// @ts-ignore
const adapter = options?.hot?.adapter;
return createMakeHot({
walk: svelte.walk,
hotApi,
adapter,
hotOptions: { noOverlay: true, .../** @type {object} */ (options.hot) }
});
}
}
/**
* @param {import('../types/options.d.ts').ResolvedOptions} options
* @returns {import('../types/compile.d.ts').CompileSvelte}
*/
export function createCompileSvelte(options) {
const makeHot = buildMakeHot(options);
return _createCompileSvelte(makeHot);
}

View File

@@ -1,26 +1,33 @@
import { createRequire } from 'node:module';
import { isSvelte5 } from './svelte-version.js';
export const SVELTE_IMPORTS = Object.entries(
createRequire(import.meta.url)('svelte/package.json').exports
)
.map(([name, config]) => {
// ignore type only
if (typeof config === 'object' && Object.keys(config).length === 1 && config.types) {
return '';
}
// ignore names
if (name === './package.json' || name === './compiler') {
return '';
}
return name.replace(/^\./, 'svelte');
})
.filter((s) => s.length > 0);
export const VITE_RESOLVE_MAIN_FIELDS = ['browser', 'module', 'jsnext:main', 'jsnext'];
export const SVELTE_RESOLVE_MAIN_FIELDS = ['svelte'];
export const SVELTE_IMPORTS = [
'svelte/animate',
'svelte/easing',
'svelte/internal',
'svelte/internal/disclose-version',
'svelte/motion',
'svelte/ssr',
'svelte/store',
'svelte/transition',
'svelte'
];
export const SVELTE_HMR_IMPORTS = [
'svelte-hmr/runtime/hot-api-esm.js',
'svelte-hmr/runtime/proxy-adapter-dom.js',
'svelte-hmr'
];
if (isSvelte5) {
SVELTE_IMPORTS.push('svelte/server', 'svelte/internal/server', 'svelte/legacy');
SVELTE_HMR_IMPORTS.length = 0; // truncate, svelte-hmr isn't used with svelte5
}
export const SVELTE_EXPORT_CONDITIONS = ['svelte'];
export const FAQ_LINK_MISSING_EXPORTS_CONDITION =
'https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/faq.md#missing-exports-condition';
export const DEFAULT_SVELTE_EXT = ['.svelte'];
export const DEFAULT_SVELTE_MODULE_INFIX = ['.svelte.'];
export const DEFAULT_SVELTE_MODULE_EXT = ['.js', '.ts'];

View File

@@ -46,6 +46,7 @@ const COMMON_DEPENDENCIES_WITHOUT_SVELTE_FIELD = [
'svelte',
'svelte2tsx',
'svelte-check',
'svelte-hmr',
'svelte-preprocess',
'tslib',
'typescript',

View File

@@ -2,7 +2,7 @@ import { buildExtendedLogMessage } from './log.js';
/**
* convert an error thrown by svelte.compile to a RollupError so that vite displays it in a user friendly way
* @param {import('svelte/compiler').Warning & Error & {frame?: string}} error a svelte compiler error, which is a mix of Warning and an error
* @param {import('svelte/types/compiler/interfaces').Warning & Error} error a svelte compiler error, which is a mix of Warning and an error
* @param {import('../types/options.d.ts').ResolvedOptions} options
* @returns {import('vite').Rollup.RollupError} the converted error
*/
@@ -29,7 +29,7 @@ export function toRollupError(error, options) {
/**
* convert an error thrown by svelte.compile to an esbuild PartialMessage
* @param {import('svelte/compiler').Warning & Error & {frame?: string}} error a svelte compiler error, which is a mix of Warning and an error
* @param {import('svelte/types/compiler/interfaces').Warning & Error} error a svelte compiler error, which is a mix of Warning and an error
* @param {import('../types/options.d.ts').ResolvedOptions} options
* @returns {import('esbuild').PartialMessage} the converted error
*/
@@ -102,17 +102,7 @@ function formatFrameForVite(frame) {
}
/**
*
* @param {string} code the svelte error code
* @see https://github.com/sveltejs/svelte/blob/main/packages/svelte/src/compiler/errors.js
* @returns {boolean}
*/
function couldBeFixedByCssPreprocessor(code) {
return code === 'expected_token' || code === 'unexpected_eof' || code?.startsWith('css_');
}
/**
* @param {import('svelte/compiler').Warning & Error} err a svelte compiler error, which is a mix of Warning and an error
* @param {import('svelte/types/compiler/interfaces').Warning & Error} err a svelte compiler error, which is a mix of Warning and an error
* @param {string} originalCode
* @param {import('../public.d.ts').Options['preprocess']} [preprocessors]
*/
@@ -122,8 +112,37 @@ export function enhanceCompileError(err, originalCode, preprocessors) {
/** @type {string[]} */
const additionalMessages = [];
// Handle incorrect TypeScript usage
if (err.code === 'parse-error') {
// Reference from Svelte: https://github.com/sveltejs/svelte/blob/9926347ad9dbdd0f3324d5538e25dcb7f5e442f8/packages/svelte/src/compiler/preprocess/index.js#L259
const scriptRe =
/<!--[^]*?-->|<script((?:\s+[^=>'"/]+=(?:"[^"]*"|'[^']*'|[^>\s]+)|\s+[^=>'"/]+)*\s*)(?:\/>|>([\S\s]*?)<\/script>)/g;
const errIndex = err.pos ?? -1;
let m;
while ((m = scriptRe.exec(originalCode))) {
const matchStart = m.index;
const matchEnd = matchStart + m[0].length;
const isErrorInScript = matchStart <= errIndex && errIndex <= matchEnd;
if (isErrorInScript) {
// Warn missing lang="ts"
const hasLangTs = m[1]?.includes('lang="ts"');
if (!hasLangTs) {
additionalMessages.push('Did you forget to add lang="ts" to your script tag?');
}
// Warn missing script preprocessor
if (preprocessors.every((p) => p.script == null)) {
const preprocessorType = hasLangTs ? 'TypeScript' : 'script';
additionalMessages.push(
`Did you forget to add a ${preprocessorType} preprocessor? See https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/preprocess.md for more information.`
);
}
}
}
}
// Handle incorrect CSS preprocessor usage
if (couldBeFixedByCssPreprocessor(err.code)) {
if (err.code === 'css-syntax-error') {
// Reference from Svelte: https://github.com/sveltejs/svelte/blob/9926347ad9dbdd0f3324d5538e25dcb7f5e442f8/packages/svelte/src/compiler/preprocess/index.js#L257
const styleRe =
/<!--[^]*?-->|<style((?:\s+[^=>'"/]+=(?:"[^"]*"|'[^']*'|[^>\s]+)|\s+[^=>'"/]+)*\s*)(?:\/>|>([\S\s]*?)<\/style>)/g;

View File

@@ -2,8 +2,7 @@ import { readFileSync } from 'node:fs';
import * as svelte from 'svelte/compiler';
import { log } from './log.js';
import { toESBuildError } from './error.js';
import { safeBase64Hash } from './hash.js';
import { normalize } from './id.js';
import { isSvelte5 } from './svelte-version.js';
/**
* @typedef {NonNullable<import('vite').DepOptimizationOptions['esbuildOptions']>} EsbuildOptions
@@ -11,7 +10,8 @@ import { normalize } from './id.js';
*/
export const facadeEsbuildSveltePluginName = 'vite-plugin-svelte:facade';
export const facadeEsbuildSvelteModulePluginName = 'vite-plugin-svelte-module:facade';
const svelteModuleExtension = '.svelte.js';
/**
* @param {import('../types/options.d.ts').ResolvedOptions} options
@@ -25,15 +25,19 @@ export function esbuildSveltePlugin(options) {
// Otherwise this would heavily slow down the scanning phase.
if (build.initialOptions.plugins?.some((v) => v.name === 'vite:dep-scan')) return;
const filter = /\.svelte(?:\?.*)?$/;
const svelteExtensions = (options.extensions ?? ['.svelte']).map((ext) => ext.slice(1));
if (isSvelte5) {
svelteExtensions.push(svelteModuleExtension.slice(1));
}
const svelteFilter = new RegExp('\\.(' + svelteExtensions.join('|') + ')(\\?.*)?$');
/** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection | undefined} */
let statsCollection;
build.onStart(() => {
statsCollection = options.stats?.startCollection('prebundle library components', {
statsCollection = options.stats?.startCollection('prebundle libraries', {
logResult: (c) => c.stats.length > 1
});
});
build.onLoad({ filter }, async ({ path: filename }) => {
build.onLoad({ filter: svelteFilter }, async ({ path: filename }) => {
const code = readFileSync(filename, 'utf8');
try {
const contents = await compileSvelte(options, { filename, code }, statsCollection);
@@ -51,30 +55,39 @@ export function esbuildSveltePlugin(options) {
/**
* @param {import('../types/options.d.ts').ResolvedOptions} options
* @param {{ filename: string, code: string }} input
* @param {{ filename: string; code: string }} input
* @param {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection} [statsCollection]
* @returns {Promise<string>}
*/
async function compileSvelte(options, { filename, code }, statsCollection) {
if (isSvelte5 && filename.endsWith(svelteModuleExtension)) {
const endStat = statsCollection?.start(filename);
// @ts-expect-error compileModule does not exist in svelte4
const compiled = svelte.compileModule(code, {
filename,
generate: 'client'
});
if (endStat) {
endStat();
}
return compiled.js.map
? compiled.js.code + '//# sourceMappingURL=' + compiled.js.map.toUrl()
: compiled.js.code;
}
let css = options.compilerOptions.css;
if (css !== 'injected') {
if (css !== 'none') {
// TODO ideally we'd be able to externalize prebundled styles too, but for now always put them in the js
css = 'injected';
}
/** @type {import('svelte/compiler').CompileOptions} */
const compileOptions = {
dev: true, // default to dev: true because prebundling is only used in dev
...options.compilerOptions,
css,
filename,
generate: 'client'
// @ts-expect-error svelte4 uses 'dom', svelte5 uses 'client'
generate: isSvelte5 ? 'client' : 'dom'
};
if (compileOptions.hmr && options.emitCss) {
const hash = `s-${safeBase64Hash(normalize(filename, options.root))}`;
compileOptions.cssHash = () => hash;
}
let preprocessed;
if (options.preprocess) {
@@ -118,60 +131,3 @@ async function compileSvelte(options, { filename, code }, statsCollection) {
? compiled.js.code + '//# sourceMappingURL=' + compiled.js.map.toUrl()
: compiled.js.code;
}
/**
* @param {import('../types/options.d.ts').ResolvedOptions} options
* @returns {EsbuildPlugin}
*/
export function esbuildSvelteModulePlugin(options) {
return {
name: 'vite-plugin-svelte-module:optimize-svelte',
setup(build) {
// Skip in scanning phase as Vite already handles scanning Svelte files.
// Otherwise this would heavily slow down the scanning phase.
if (build.initialOptions.plugins?.some((v) => v.name === 'vite:dep-scan')) return;
const filter = /\.svelte\.[jt]s(?:\?.*)?$/;
/** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection | undefined} */
let statsCollection;
build.onStart(() => {
statsCollection = options.stats?.startCollection('prebundle library modules', {
logResult: (c) => c.stats.length > 1
});
});
build.onLoad({ filter }, async ({ path: filename }) => {
const code = readFileSync(filename, 'utf8');
try {
const contents = await compileSvelteModule(options, { filename, code }, statsCollection);
return { contents };
} catch (e) {
return { errors: [toESBuildError(e, options)] };
}
});
build.onEnd(() => {
statsCollection?.finish();
});
}
};
}
/**
* @param {import('../types/options.d.ts').ResolvedOptions} options
* @param {{ filename: string; code: string }} input
* @param {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection} [statsCollection]
* @returns {Promise<string>}
*/
async function compileSvelteModule(options, { filename, code }, statsCollection) {
const endStat = statsCollection?.start(filename);
const compiled = svelte.compileModule(code, {
dev: options.compilerOptions?.dev ?? true, // default to dev: true because prebundling is only used in dev
filename,
generate: 'client'
});
if (endStat) {
endStat();
}
return compiled.js.map
? compiled.js.code + '//# sourceMappingURL=' + compiled.js.map.toUrl()
: compiled.js.code;
}

View File

@@ -1,4 +1,4 @@
import crypto from 'node:crypto';
import * as crypto from 'node:crypto';
const hashes = Object.create(null);

View File

@@ -1,14 +1,19 @@
import { createFilter, normalizePath } from 'vite';
import fs from 'node:fs';
import path from 'node:path';
import process from 'node:process';
import * as fs from 'node:fs';
import { log } from './log.js';
import { DEFAULT_SVELTE_MODULE_EXT, DEFAULT_SVELTE_MODULE_INFIX } from './constants.js';
const VITE_FS_PREFIX = '/@fs/';
const IS_WINDOWS = process.platform === 'win32';
const SUPPORTED_COMPILER_OPTIONS = ['generate', 'dev', 'css', 'customElement', 'immutable'];
const SUPPORTED_COMPILER_OPTIONS = [
'generate',
'dev',
'css',
'hydratable',
'customElement',
'immutable',
'enableSourcemap'
];
const TYPES_WITH_COMPILER_OPTIONS = ['style', 'script', 'all'];
/**
@@ -84,7 +89,7 @@ function parseRequestQuery(rawQuery) {
const query = Object.fromEntries(new URLSearchParams(rawQuery));
for (const key in query) {
if (query[key] === '') {
// @ts-expect-error not boolean
// @ts-ignore
query[key] = true;
}
}
@@ -94,7 +99,7 @@ function parseRequestQuery(rawQuery) {
throw new Error(
`Invalid compilerOptions in query ${rawQuery}. CompilerOptions are only supported for raw or direct queries with type in "${TYPES_WITH_COMPILER_OPTIONS.join(
', '
)}" e.g. '?svelte&raw&type=script&compilerOptions={"generate":"server","dev":false}`
)}" e.g. '?svelte&raw&type=script&compilerOptions={"generate":"ssr","dev":false}`
);
}
try {
@@ -126,7 +131,7 @@ function parseRequestQuery(rawQuery) {
* @param {string} normalizedRoot
* @returns {string}
*/
export function normalize(filename, normalizedRoot) {
function normalize(filename, normalizedRoot) {
return stripRoot(normalizePath(filename), normalizedRoot);
}
@@ -164,26 +169,6 @@ function buildFilter(include, exclude, extensions) {
return (filename) => rollupFilter(filename) && extensions.some((ext) => filename.endsWith(ext));
}
/**
* @param {import('../public.d.ts').Options['include'] | undefined} include
* @param {import('../public.d.ts').Options['exclude'] | undefined} exclude
* @param {string[]} infixes
* @param {string[]} extensions
* @returns {(filename: string) => boolean}
*/
function buildModuleFilter(include, exclude, infixes, extensions) {
const rollupFilter = createFilter(include, exclude);
return (filename) => {
const basename = path.basename(filename);
return (
rollupFilter(filename) &&
infixes.some((infix) => basename.includes(infix)) &&
extensions.some((ext) => basename.endsWith(ext))
);
};
}
/**
* @param {import('../types/options.d.ts').ResolvedOptions} options
* @returns {import('../types/id.d.ts').IdParser}
@@ -205,15 +190,10 @@ export function buildIdParser(options) {
* @returns {import('../types/id.d.ts').ModuleIdParser}
*/
export function buildModuleIdParser(options) {
const {
include,
exclude,
infixes = DEFAULT_SVELTE_MODULE_INFIX,
extensions = DEFAULT_SVELTE_MODULE_EXT
} = options?.experimental?.compileModule ?? {};
const { include, exclude, extensions } = options?.experimental?.compileModule ?? {};
const root = options.root;
const normalizedRoot = normalizePath(root);
const filter = buildModuleFilter(include, exclude, infixes, extensions);
const filter = buildFilter(include, exclude, extensions ?? ['.svelte.js', '.svelte.ts']);
return (id, ssr, timestamp = Date.now()) => {
const { filename, rawQuery } = splitId(id);
if (filter(filename)) {

View File

@@ -1,7 +1,7 @@
import fs from 'node:fs';
import { toRollupError } from './error.js';
import { log } from './log.js';
import { isSvelte4, isSvelte5 } from './svelte-version.js';
/**
* utility function to compile ?raw and ?direct requests in load hook
*
@@ -18,16 +18,26 @@ export async function loadRaw(svelteRequest, compileSvelte, options) {
const source = fs.readFileSync(filename, 'utf-8');
try {
//avoid compileSvelte doing extra ssr stuff unless requested
svelteRequest.ssr = query.compilerOptions?.generate === 'server';
//@ts-ignore //@ts-expect-error generate value differs between svelte4 and 5
svelteRequest.ssr = query.compilerOptions?.generate === (isSvelte4 ? 'ssr' : 'server');
const type = query.type;
compileData = await compileSvelte(svelteRequest, source, {
...options,
// don't use dynamic vite-plugin-svelte defaults here to ensure stable result between ssr,dev and build
compilerOptions: {
dev: false,
css: 'external',
hmr: false,
enableSourcemap: isSvelte5
? undefined
: query.sourcemap
? {
js: type === 'script' || type === 'all',
css: type === 'style' || type === 'all'
}
: false,
...svelteRequest.query.compilerOptions
},
hot: false,
emitCss: true
});
} catch (e) {
@@ -35,7 +45,7 @@ export async function loadRaw(svelteRequest, compileSvelte, options) {
}
let result;
if (query.type === 'style') {
result = compileData.compiled.css ?? { code: '', map: null };
result = compileData.compiled.css;
} else if (query.type === 'script') {
result = compileData.compiled.js;
} else if (query.type === 'preprocessed') {
@@ -58,9 +68,7 @@ export async function loadRaw(svelteRequest, compileSvelte, options) {
}
log.debug(`load returns direct result for ${id}`, undefined, 'load');
let directOutput = result.code;
// @ts-expect-error might not be SourceMap but toUrl check should suffice
if (query.sourcemap && result.map?.toUrl) {
// @ts-expect-error toUrl might not exist
const map = `sourceMappingURL=${result.map.toUrl()}`;
if (query.type === 'style') {
directOutput += `\n\n/*# ${map} */\n`;
@@ -114,7 +122,8 @@ function allToRawExports(compileData, source) {
function toRawExports(object) {
let exports =
Object.entries(object)
.filter(([_key, value]) => typeof value !== 'function') // preprocess output has a toString function that's enumerable
//eslint-disable-next-line no-unused-vars
.filter(([key, value]) => typeof value !== 'function') // preprocess output has a toString function that's enumerable
.sort(([a], [b]) => (a < b ? -1 : a === b ? 0 : 1))
.map(([key, value]) => `export const ${key}=${JSON.stringify(value)}`)
.join('\n') + '\n';

View File

@@ -1,6 +1,5 @@
import { createRequire } from 'node:module';
import path from 'node:path';
import process from 'node:process';
import fs from 'node:fs';
import { pathToFileURL } from 'node:url';
import { log } from './log.js';
@@ -62,7 +61,7 @@ export async function loadSvelteConfig(viteConfig, inlineOptions) {
try {
// identify which require function to use (esm and cjs mode)
const _require = import.meta.url
? (esmRequire ?? (esmRequire = createRequire(import.meta.url)))
? esmRequire ?? (esmRequire = createRequire(import.meta.url))
: // eslint-disable-next-line no-undef
require;

View File

@@ -1,6 +1,7 @@
/* eslint-disable no-console */
import { cyan, red, yellow } from 'kleur/colors';
import debug from 'debug';
import { VERSION } from 'svelte/compiler';
/** @type {import('../types/log.d.ts').LogLevel[]} */
const levels = ['debug', 'info', 'warn', 'error', 'silent'];
@@ -72,11 +73,7 @@ function _log(logger, message, payload, namespace) {
}
log = logger.log.extend(namespace);
}
if (payload !== undefined) {
log(message, payload);
} else {
log(message);
}
payload !== undefined ? log(message, payload) : log(message);
} else {
logger.log(
logger.color(
@@ -131,21 +128,21 @@ export const log = {
/**
* @param {import('../types/id.d.ts').SvelteRequest | import('../types/id.d.ts').SvelteModuleRequest} svelteRequest
* @param {import('svelte/compiler').Warning[]} warnings
* @param {import('svelte/types/compiler/interfaces').Warning[]} warnings
* @param {import('../types/options.d.ts').ResolvedOptions} options
*/
export function logCompilerWarnings(svelteRequest, warnings, options) {
const { emitCss, onwarn, isBuild } = options;
const sendViaWS = !isBuild && options.experimental?.sendWarningsToBrowser;
let warn = isBuild ? warnBuild : warnDev;
/** @type {import('svelte/compiler').Warning[]} */
/** @type {import('svelte/types/compiler/interfaces').Warning[]} */
const handledByDefaultWarn = [];
const notIgnored = warnings?.filter((w) => !ignoreCompilerWarning(w, isBuild, emitCss));
const extra = buildExtraWarnings(warnings, isBuild);
const allWarnings = [...notIgnored, ...extra];
if (sendViaWS) {
const _warn = warn;
/** @type {(w: import('svelte/compiler').Warning) => void} */
/** @type {(w: import('svelte/types/compiler/interfaces').Warning) => void} */
warn = (w) => {
handledByDefaultWarn.push(w);
_warn(w);
@@ -175,33 +172,33 @@ export function logCompilerWarnings(svelteRequest, warnings, options) {
}
/**
* @param {import('svelte/compiler').Warning} warning
* @param {import('svelte/types/compiler/interfaces').Warning} warning
* @param {boolean} isBuild
* @param {boolean} [emitCss]
* @returns {boolean}
*/
function ignoreCompilerWarning(warning, isBuild, emitCss) {
return (
(!emitCss && warning.code === 'css_unused_selector') || // same as rollup-plugin-svelte
(!emitCss && warning.code === 'css-unused-selector') || // same as rollup-plugin-svelte
(!isBuild && isNoScopableElementWarning(warning))
);
}
/**
*
* @param {import('svelte/compiler').Warning} warning
* @param {import('svelte/types/compiler/interfaces').Warning} warning
* @returns {boolean}
*/
function isNoScopableElementWarning(warning) {
// see https://github.com/sveltejs/vite-plugin-svelte/issues/153
return warning.code === 'css_unused_selector' && warning.message.includes('"*"');
return warning.code === 'css-unused-selector' && warning.message.includes('"*"');
}
/**
*
* @param {import('svelte/compiler').Warning[]} warnings
* @param {import('svelte/types/compiler/interfaces').Warning[]} warnings
* @param {boolean} isBuild
* @returns {import('svelte/compiler').Warning[]}
* @returns {import('svelte/types/compiler/interfaces').Warning[]}
*/
function buildExtraWarnings(warnings, isBuild) {
const extraWarnings = [];
@@ -223,33 +220,21 @@ function buildExtraWarnings(warnings, isBuild) {
}
/**
* @param {import('svelte/compiler').Warning} w
* @param {import('svelte/types/compiler/interfaces').Warning} w
*/
function warnDev(w) {
if (w.filename?.includes('node_modules')) {
if (isDebugNamespaceEnabled('node-modules-onwarn')) {
log.debug(buildExtendedLogMessage(w), undefined, 'node-modules-onwarn');
}
} else if (log.info.enabled) {
log.info(buildExtendedLogMessage(w));
}
log.info.enabled && log.info(buildExtendedLogMessage(w));
}
/**
* @param {import('svelte/compiler').Warning & {frame?: string}} w
* @param {import('svelte/types/compiler/interfaces').Warning} w
*/
function warnBuild(w) {
if (w.filename?.includes('node_modules')) {
if (isDebugNamespaceEnabled('node-modules-onwarn')) {
log.debug(buildExtendedLogMessage(w), w.frame, 'node-modules-onwarn');
}
} else if (log.warn.enabled) {
log.warn(buildExtendedLogMessage(w), w.frame);
}
log.warn.enabled && log.warn(buildExtendedLogMessage(w), w.frame);
}
/**
* @param {import('svelte/compiler').Warning} w
* @param {import('svelte/types/compiler/interfaces').Warning} w
*/
export function buildExtendedLogMessage(w) {
const parts = [];
@@ -275,3 +260,12 @@ export function buildExtendedLogMessage(w) {
export function isDebugNamespaceEnabled(namespace) {
return debug.enabled(`${prefix}:${namespace}`);
}
export function logSvelte5Warning() {
log.warn(
`You are using Svelte ${VERSION} with vite-plugin-svelte@3. Active Svelte 5 support has moved to vite-plugin-svelte@4.
To receive bug fixes and new features update your devDependencies to "@sveltejs/vite-plugin-svelte": "^4.0.0-next.6" and install.
For framework integrations that depend on it, you might have to add an override:
"overrides": {"@sveltejs/vite-plugin-svelte": "^4.0.0-next.6"}`.replace(/\n\s*/gm, '\n\t')
);
}

View File

@@ -1,27 +1,18 @@
import process from 'node:process';
import {
defaultClientMainFields,
defaultServerMainFields,
defaultClientConditions,
defaultServerConditions,
normalizePath
} from 'vite';
/* eslint-disable no-unused-vars */
import { normalizePath } from 'vite';
import { isDebugNamespaceEnabled, log } from './log.js';
import { loadSvelteConfig } from './load-svelte-config.js';
import {
DEFAULT_SVELTE_EXT,
FAQ_LINK_MISSING_EXPORTS_CONDITION,
SVELTE_EXPORT_CONDITIONS,
SVELTE_IMPORTS
SVELTE_HMR_IMPORTS,
SVELTE_IMPORTS,
SVELTE_RESOLVE_MAIN_FIELDS,
VITE_RESOLVE_MAIN_FIELDS
} from './constants.js';
import path from 'node:path';
import {
esbuildSvelteModulePlugin,
esbuildSveltePlugin,
facadeEsbuildSvelteModulePluginName,
facadeEsbuildSveltePluginName
} from './esbuild.js';
import { esbuildSveltePlugin, facadeEsbuildSveltePluginName } from './esbuild.js';
import { addExtraPreprocessors } from './preprocess.js';
import deepmerge from 'deepmerge';
import {
@@ -34,6 +25,8 @@ import {
import { isCommonDepWithoutSvelteField } from './dependencies.js';
import { VitePluginSvelteStats } from './vite-plugin-svelte-stats.js';
import { VitePluginSvelteCache } from './vite-plugin-svelte-cache.js';
import { isSvelte5, isSvelte5WithHMRSupport } from './svelte-version.js';
const allowedPluginOptions = new Set([
'include',
@@ -112,7 +105,7 @@ function convertPluginOptions(config) {
)}`
);
unknownPluginOptions.forEach((unkownOption) => {
// @ts-expect-error not typed
// @ts-ignore
delete pluginOptions[unkownOption];
});
}
@@ -146,7 +139,7 @@ export async function preResolveOptions(inlineOptions, viteUserConfig, viteEnv)
const isBuild = viteEnv.command === 'build';
/** @type {Partial<import('../types/options.d.ts').PreResolvedOptions>} */
const defaultOptions = {
extensions: DEFAULT_SVELTE_EXT,
extensions: ['.svelte'],
emitCss: true,
prebundleSvelteLibraries: !isBuild
};
@@ -194,7 +187,7 @@ function mergeConfigs(...configs) {
*
* @param {import('../types/options.d.ts').PreResolvedOptions} preResolveOptions
* @param {import('vite').ResolvedConfig} viteConfig
* @param {import('./vite-plugin-svelte-cache.js').VitePluginSvelteCache} cache
* @param {VitePluginSvelteCache} cache
* @returns {import('../types/options.d.ts').ResolvedOptions}
*/
export function resolveOptions(preResolveOptions, viteConfig, cache) {
@@ -203,15 +196,24 @@ export function resolveOptions(preResolveOptions, viteConfig, cache) {
const defaultOptions = {
compilerOptions: {
css,
dev: !viteConfig.isProduction,
hmr:
!viteConfig.isProduction &&
!preResolveOptions.isBuild &&
viteConfig.server &&
viteConfig.server.hmr !== false
dev: !viteConfig.isProduction
}
};
const hot =
!viteConfig.isProduction && !preResolveOptions.isBuild && viteConfig.server.hmr !== false;
if (isSvelte5) {
if (isSvelte5WithHMRSupport) {
// @ts-expect-error svelte4 does not have hmr option
defaultOptions.compilerOptions.hmr = hot;
}
} else {
defaultOptions.hot = !hot
? false
: {
injectCss: css === 'injected',
partialAccept: !!viteConfig.experimental?.hmrPartialAccept
};
}
/** @type {Partial<import('../types/options.d.ts').ResolvedOptions>} */
const extraOptions = {
root: viteConfig.root,
@@ -238,18 +240,61 @@ export function resolveOptions(preResolveOptions, viteConfig, cache) {
* @param {import('vite').ResolvedConfig} viteConfig
*/
function enforceOptionsForHmr(options, viteConfig) {
if (options.hot) {
if (options.hot && viteConfig.server.hmr === false) {
log.warn(
'svelte 5 has hmr integrated in core. Please remove the vitePlugin.hot option and use compilerOptions.hmr instead'
'vite config server.hmr is false but hot is true. Forcing hot to false as it would not work.'
);
delete options.hot;
options.compilerOptions.hmr = true;
options.hot = false;
}
if (options.compilerOptions.hmr && viteConfig.server?.hmr === false) {
log.warn(
'vite config server.hmr is false but compilerOptions.hmr is true. Forcing compilerOptions.hmr to false as it would not work.'
);
options.compilerOptions.hmr = false;
if (isSvelte5) {
if (options.hot && isSvelte5WithHMRSupport) {
log.warn(
'svelte 5 has hmr integrated in core. Please remove the hot option and use compilerOptions.hmr instead'
);
delete options.hot;
// @ts-expect-error hmr option doesn't exist in svelte4
options.compilerOptions.hmr = true;
}
} else {
if (options.hot) {
if (!options.compilerOptions.dev) {
log.warn('hmr is enabled but compilerOptions.dev is false, forcing it to true');
options.compilerOptions.dev = true;
}
if (options.emitCss) {
if (options.hot !== true && options.hot.injectCss) {
log.warn('hmr and emitCss are enabled but hot.injectCss is true, forcing it to false');
options.hot.injectCss = false;
}
const css = options.compilerOptions.css;
if (css === true || css === 'injected') {
const forcedCss = 'external';
log.warn(
`hmr and emitCss are enabled but compilerOptions.css is ${css}, forcing it to ${forcedCss}`
);
options.compilerOptions.css = forcedCss;
}
} else {
if (options.hot === true || !options.hot.injectCss) {
log.warn(
'hmr with emitCss disabled requires option hot.injectCss to be enabled, forcing it to true'
);
if (options.hot === true) {
options.hot = { injectCss: true };
} else {
options.hot.injectCss = true;
}
}
const css = options.compilerOptions.css;
if (!(css === true || css === 'injected')) {
const forcedCss = 'injected';
log.warn(
`hmr with emitCss disabled requires compilerOptions.css to be enabled, forcing it to ${forcedCss}`
);
options.compilerOptions.css = forcedCss;
}
}
}
}
}
@@ -258,11 +303,9 @@ function enforceOptionsForHmr(options, viteConfig) {
*/
function enforceOptionsForProduction(options) {
if (options.isProduction) {
if (options.compilerOptions.hmr) {
log.warn(
'you are building for production but compilerOptions.hmr is true, forcing it to false'
);
options.compilerOptions.hmr = false;
if (options.hot) {
log.warn('options.hot is enabled but does not work on production build, forcing it to false');
options.hot = false;
}
if (options.compilerOptions.dev) {
log.warn(
@@ -278,7 +321,7 @@ function enforceOptionsForProduction(options) {
*/
function removeIgnoredOptions(options) {
const ignoredCompilerOptions = ['generate', 'format', 'filename'];
if (options.compilerOptions.hmr && options.emitCss) {
if (options.hot && options.emitCss) {
ignoredCompilerOptions.push('cssHash');
}
const passedCompilerOptions = Object.keys(options.compilerOptions || {});
@@ -337,13 +380,25 @@ function resolveViteRoot(viteConfig) {
* @returns {Promise<Partial<import('vite').UserConfig>>}
*/
export async function buildExtraViteConfig(options, config) {
// make sure we only readd vite default mainFields when no other plugin has changed the config already
// see https://github.com/sveltejs/vite-plugin-svelte/issues/581
if (!config.resolve) {
config.resolve = {};
}
config.resolve.mainFields = [
...SVELTE_RESOLVE_MAIN_FIELDS,
...(config.resolve.mainFields ?? VITE_RESOLVE_MAIN_FIELDS)
];
/** @type {Partial<import('vite').UserConfig>} */
const extraViteConfig = {
resolve: {
dedupe: [...SVELTE_IMPORTS]
dedupe: [...SVELTE_IMPORTS, ...SVELTE_HMR_IMPORTS],
conditions: [...SVELTE_EXPORT_CONDITIONS]
}
// this option is still awaiting a PR in vite to be supported
// see https://github.com/sveltejs/vite-plugin-svelte/issues/60
// @ts-ignore
// knownJsSrcExtensions: options.extensions
};
@@ -385,21 +440,24 @@ export async function buildExtraViteConfig(options, config) {
extraViteConfig.optimizeDeps = {
...extraViteConfig.optimizeDeps,
// Experimental Vite API to allow these extensions to be scanned and prebundled
// @ts-ignore
extensions: options.extensions ?? ['.svelte'],
// Add esbuild plugin to prebundle Svelte files.
// Currently a placeholder as more information is needed after Vite config is resolved,
// the real Svelte plugin is added in `patchResolvedViteConfig()`
esbuildOptions: {
plugins: [
{ name: facadeEsbuildSveltePluginName, setup: () => {} },
{ name: facadeEsbuildSvelteModulePluginName, setup: () => {} }
]
plugins: [{ name: facadeEsbuildSveltePluginName, setup: () => {} }]
}
};
}
// enable hmrPartialAccept if not explicitly disabled
if (config.experimental?.hmrPartialAccept !== false) {
if (
(options.hot == null ||
options.hot === true ||
(options.hot && options.hot.partialAccept !== false)) && // deviate from svelte-hmr, default to true
config.experimental?.hmrPartialAccept !== false
) {
log.debug('enabling "experimental.hmrPartialAccept" in vite config', undefined, 'config');
extraViteConfig.experimental = { hmrPartialAccept: true };
}
@@ -544,12 +602,9 @@ function buildExtraConfigForSvelte(config) {
// include svelte imports for optimization unless explicitly excluded
/** @type {string[]} */
const include = [];
/** @type {string[]} */
const exclude = [];
const exclude = ['svelte-hmr'];
if (!isDepExcluded('svelte', config.optimizeDeps?.exclude ?? [])) {
const svelteImportsToInclude = SVELTE_IMPORTS.filter(
(si) => !(si.endsWith('/server') || si.includes('/server/'))
);
const svelteImportsToInclude = SVELTE_IMPORTS.filter((x) => x !== 'svelte/ssr'); // not used on clientside
log.debug(
`adding bare svelte packages to optimizeDeps.include: ${svelteImportsToInclude.join(', ')} `,
undefined,
@@ -568,15 +623,10 @@ function buildExtraConfigForSvelte(config) {
/** @type {string[]} */
const external = [];
// add svelte to ssr.noExternal unless it is present in ssr.external
// so it is correctly resolving according to the conditions in sveltes exports map
// so we can resolve it with svelte/ssr
if (!isDepExternaled('svelte', config.ssr?.external ?? [])) {
noExternal.push('svelte', /^svelte\//);
}
// esm-env needs to be bundled by default for the development/production condition
// be properly used by svelte
if (!isDepExternaled('esm-env', config.ssr?.external ?? [])) {
noExternal.push('esm-env');
}
return { optimizeDeps: { include, exclude }, ssr: { noExternal, external } };
}
@@ -600,47 +650,6 @@ export function patchResolvedViteConfig(viteConfig, options) {
if (facadeEsbuildSveltePlugin) {
Object.assign(facadeEsbuildSveltePlugin, esbuildSveltePlugin(options));
}
const facadeEsbuildSvelteModulePlugin = viteConfig.optimizeDeps.esbuildOptions?.plugins?.find(
(plugin) => plugin.name === facadeEsbuildSvelteModulePluginName
);
if (facadeEsbuildSvelteModulePlugin) {
Object.assign(facadeEsbuildSvelteModulePlugin, esbuildSvelteModulePlugin(options));
}
}
/**
* Mutates `config` to ensure `resolve.mainFields` is set. If unset, it emulates Vite's default fallback.
* @param {string} name
* @param {import('vite').EnvironmentOptions} config
* @param {{ isSsrTargetWebworker?: boolean }} opts
*/
export function ensureConfigEnvironmentMainFields(name, config, opts) {
config.resolve ??= {};
if (config.resolve.mainFields == null) {
if (config.consumer === 'client' || name === 'client' || opts.isSsrTargetWebworker) {
config.resolve.mainFields = [...defaultClientMainFields];
} else {
config.resolve.mainFields = [...defaultServerMainFields];
}
}
return true;
}
/**
* Mutates `config` to ensure `resolve.conditions` is set. If unset, it emulates Vite's default fallback.
* @param {string} name
* @param {import('vite').EnvironmentOptions} config
* @param {{ isSsrTargetWebworker?: boolean }} opts
*/
export function ensureConfigEnvironmentConditions(name, config, opts) {
config.resolve ??= {};
if (config.resolve.conditions == null) {
if (config.consumer === 'client' || name === 'client' || opts.isSsrTargetWebworker) {
config.resolve.conditions = [...defaultClientConditions];
} else {
config.resolve.conditions = [...defaultServerConditions];
}
}
}
/**

View File

@@ -42,7 +42,7 @@ function buildExtraPreprocessors(options, config) {
/** @type {import('svelte/compiler').PreprocessorGroup[]} */
const appendPreprocessors = [];
// @ts-expect-error not typed
// @ts-ignore
const pluginsWithPreprocessorsDeprecated = config.plugins.filter((p) => p?.sveltePreprocess);
if (pluginsWithPreprocessorsDeprecated.length > 0) {
log.warn(
@@ -56,7 +56,7 @@ function buildExtraPreprocessors(options, config) {
p.api = {};
}
if (p.api.sveltePreprocess === undefined) {
// @ts-expect-error not typed
// @ts-ignore
p.api.sveltePreprocess = p.sveltePreprocess;
} else {
log.error(
@@ -127,10 +127,10 @@ export function addExtraPreprocessors(options, config) {
*
* @param filename {string}
* @param dependencies {string[]}
* @returns {({dependencies: string[], warnings:import('svelte/compiler').Warning[] })}
* @returns {({dependencies: string[], warnings:import('svelte/types/compiler/interfaces').Warning[] })}
*/
export function checkPreprocessDependencies(filename, dependencies) {
/** @type {import('svelte/compiler').Warning[]} */
/** @type {import('svelte/types/compiler/interfaces').Warning[]} */
const warnings = [];
// to find self, we have to compare normalized filenames, but must keep the original values in `dependencies`

View File

@@ -1,5 +1,4 @@
import path from 'node:path';
import process from 'node:process';
const IS_WINDOWS = process.platform === 'win32';

View File

@@ -1,5 +1,10 @@
import { VERSION } from 'svelte/compiler';
/**
* @type {boolean}
*/
export const isSvelte4 = VERSION.startsWith('4.');
/**
* @type {boolean}
*/

View File

@@ -16,9 +16,9 @@ import { normalizePath } from 'vite';
* @class
*/
export class VitePluginSvelteCache {
/** @type {Map<string, import('../types/compile.d.ts').Code | null>} */
/** @type {Map<string, import('../types/compile.d.ts').Code>} */
#css = new Map();
/** @type {Map<string, import('../types/compile.d.ts').Code | null>} */
/** @type {Map<string, import('../types/compile.d.ts').Code>} */
#js = new Map();
/** @type {Map<string, string[]>} */
#dependencies = new Map();
@@ -133,7 +133,7 @@ export class VitePluginSvelteCache {
/**
* @param {import('../types/id.d.ts').SvelteRequest} svelteRequest
* @returns {import('../types/compile.d.ts').Code | undefined | null}
* @returns {import('../types/compile.d.ts').Code | undefined}
*/
getCSS(svelteRequest) {
return this.#css.get(svelteRequest.normalizedFilename);
@@ -141,7 +141,7 @@ export class VitePluginSvelteCache {
/**
* @param {import('../types/id.d.ts').SvelteRequest} svelteRequest
* @returns {import('../types/compile.d.ts').Code | undefined | null}
* @returns {import('../types/compile.d.ts').Code | undefined}
*/
getJS(svelteRequest) {
if (!svelteRequest.ssr) {

View File

@@ -89,7 +89,6 @@ export class VitePluginSvelteStats {
/** @type {import('../types/vite-plugin-svelte-stats.d.ts').Stat[]} */
const stats = [];
const collectionStart = performance.now();
const _this = this;
let hasLoggedProgress = false;
/** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection} */

View File

@@ -22,7 +22,7 @@ export function setupWatchers(options, cache, requestParser) {
dependants.forEach((dependant) => {
if (fs.existsSync(dependant)) {
log.debug(
`emitting virtual change event for "${dependant}" because dependency "${filename}" changed`,
`emitting virtual change event for "${dependant}" because depdendency "${filename}" changed`,
undefined,
'hmr'
);

View File

@@ -1,6 +1,7 @@
declare module '@sveltejs/vite-plugin-svelte' {
import type { InlineConfig, ResolvedConfig } from 'vite';
import type { CompileOptions, Warning, PreprocessorGroup } from 'svelte/compiler';
import type { CompileOptions, PreprocessorGroup } from 'svelte/compiler';
import type { Warning } from 'svelte/types/compiler/interfaces';
import type { Options as InspectorOptions } from '@sveltejs/vite-plugin-svelte-inspector';
export type Options = Omit<SvelteConfig, 'vitePlugin'> & PluginOptionsInline;
@@ -15,7 +16,7 @@ declare module '@sveltejs/vite-plugin-svelte' {
configFile?: string | false;
}
export interface PluginOptions {
interface PluginOptions {
/**
* A `picomatch` pattern, or array of patterns, which specifies the files the plugin should
* operate on. By default, all svelte files are included.
@@ -38,13 +39,27 @@ declare module '@sveltejs/vite-plugin-svelte' {
emitCss?: boolean;
/**
* Enable or disable Hot Module Replacement.
* Deprecated, use compilerOptions.hmr instead!
*
* @deprecated
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
* DO NOT CUSTOMIZE SVELTE-HMR OPTIONS UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING
*
* YOU HAVE BEEN WARNED
*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
* Set an object to pass custom options to svelte-hmr
*
* @see https://github.com/rixo/svelte-hmr#options
* @default true for development, always false for production
*/
hot?: boolean;
hot?:
| boolean
| {
injectCss?: boolean;
partialAccept?: boolean;
[key: string]: any;
};
/**
* Some Vite plugins can contribute additional preprocessors by defining `api.sveltePreprocess`.
* If you don't want to use them, set this to true to ignore them all or use an array of strings
@@ -92,9 +107,9 @@ declare module '@sveltejs/vite-plugin-svelte' {
* @example
* ```
* ({ filename, compileOptions }) => {
* // Dynamically set runes mode per Svelte file
* if (forceRunesMode(filename) && !compileOptions.runes) {
* return { runes: true };
* // Dynamically set hydration per Svelte file
* if (compileWithHydratable(filename) && !compileOptions.hydratable) {
* return { hydratable: true };
* }
* }
* ```
@@ -135,22 +150,8 @@ declare module '@sveltejs/vite-plugin-svelte' {
/**
* Handles warning emitted from the Svelte compiler
*
* warnings emitted for files in node_modules are logged at the debug level, to see them run
* `DEBUG=vite-plugin-svelte:node-modules-onwarn pnpm build`
*
* @example
* ```
* (warning, defaultHandler) => {
* // ignore some warnings
* if (!['foo','bar'].includes(warning.code)) {
* defaultHandler(warning);
* }
* }
* ```
*
*/
onwarn?: (warning: Warning, defaultHandler: (warning: Warning) => void) => void;
onwarn?: (warning: Warning, defaultHandler?: (warning: Warning) => void) => void;
/**
* Options for vite-plugin-svelte
*/
@@ -177,15 +178,6 @@ declare module '@sveltejs/vite-plugin-svelte' {
}
interface CompileModuleOptions {
/**
* infix that must be present in filename
* @default ['.svelte.']
*/
infixes?: string[];
/**
* module extensions
* @default ['.ts','.js']
*/
extensions?: string[];
include?: Arrayable<string>;
exclude?: Arrayable<string>;
@@ -194,23 +186,12 @@ declare module '@sveltejs/vite-plugin-svelte' {
type Arrayable<T> = T | T[];
export interface VitePreprocessOptions {
/**
* preprocess script block with vite pipeline.
* Since svelte5 this is not needed for typescript anymore
*
* @default false
*/
script?: boolean;
/**
* preprocess style blocks with vite pipeline
*/
style?: boolean | InlineConfig | ResolvedConfig;
}
export function svelte(inlineOptions?: Partial<Options>): import("vite").Plugin[];
export function vitePreprocess(opts?: VitePreprocessOptions): import("svelte/compiler").PreprocessorGroup;
export function loadSvelteConfig(viteConfig?: import("vite").UserConfig, inlineOptions?: Partial<Options>): Promise<Partial<SvelteConfig> | undefined>;
export {};
export function svelte(inlineOptions?: Partial<Options> | undefined): import('vite').Plugin[];
export function vitePreprocess(opts?: VitePreprocessOptions | undefined): import('svelte/compiler').PreprocessorGroup;
export function loadSvelteConfig(viteConfig?: import("vite").UserConfig | undefined, inlineOptions?: Partial<Options> | undefined): Promise<Partial<SvelteConfig> | undefined>;
}
//# sourceMappingURL=index.d.ts.map

View File

@@ -3,7 +3,6 @@
"file": "index.d.ts",
"names": [
"Options",
"PluginOptions",
"SvelteConfig",
"VitePreprocessOptions",
"svelte",
@@ -22,6 +21,5 @@
null,
null
],
"mappings": ";;;;aAIYA,OAAOA;;;;;;;;;;;;;kBAaFC,aAAaA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAgGbC,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAkFZC,qBAAqBA;;;;;;;;;;;;;iBCxKtBC,MAAMA;iBCXNC,cAAcA;iBCgBRC,gBAAgBA",
"ignoreList": []
"mappings": ";;;;;aAMYA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA2HFC,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA2DZC,qBAAqBA;;;;iBChKtBC,MAAMA;iBCbNC,cAAcA;iBCgBRC,gBAAgBA"
}