@sveltejs/vite-plugin-svelte 1.0.0-next.9 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts ADDED
@@ -0,0 +1,242 @@
1
+ import fs from 'fs';
2
+ import { HmrContext, ModuleNode, Plugin, ResolvedConfig, UserConfig } from 'vite';
3
+ import { handleHotUpdate } from './handle-hot-update';
4
+ import { log, logCompilerWarnings } from './utils/log';
5
+ import { CompileData, createCompileSvelte } from './utils/compile';
6
+ import { buildIdParser, IdParser, SvelteRequest } from './utils/id';
7
+ import {
8
+ buildExtraViteConfig,
9
+ validateInlineOptions,
10
+ Options,
11
+ ResolvedOptions,
12
+ resolveOptions,
13
+ patchResolvedViteConfig,
14
+ preResolveOptions
15
+ } from './utils/options';
16
+ import { VitePluginSvelteCache } from './utils/vite-plugin-svelte-cache';
17
+
18
+ import { ensureWatchedFile, setupWatchers } from './utils/watch';
19
+ import { resolveViaPackageJsonSvelte } from './utils/resolve';
20
+ import { PartialResolvedId } from 'rollup';
21
+ import { toRollupError } from './utils/error';
22
+ import { saveSvelteMetadata } from './utils/optimizer';
23
+ import { svelteInspector } from './ui/inspector/plugin';
24
+
25
+ interface PluginAPI {
26
+ /**
27
+ * must not be modified, should not be used outside of vite-plugin-svelte repo
28
+ * @internal
29
+ * @experimental
30
+ */
31
+ options?: ResolvedOptions;
32
+ // TODO expose compile cache here so other utility plugins can use it
33
+ }
34
+
35
+ export function svelte(inlineOptions?: Partial<Options>): Plugin[] {
36
+ if (process.env.DEBUG != null) {
37
+ log.setLevel('debug');
38
+ }
39
+ validateInlineOptions(inlineOptions);
40
+ const cache = new VitePluginSvelteCache();
41
+ // updated in configResolved hook
42
+ let requestParser: IdParser;
43
+ let options: ResolvedOptions;
44
+ let viteConfig: ResolvedConfig;
45
+ /* eslint-disable no-unused-vars */
46
+ let compileSvelte: (
47
+ svelteRequest: SvelteRequest,
48
+ code: string,
49
+ options: Partial<ResolvedOptions>
50
+ ) => Promise<CompileData>;
51
+ /* eslint-enable no-unused-vars */
52
+
53
+ let resolvedSvelteSSR: Promise<PartialResolvedId | null>;
54
+ const api: PluginAPI = {};
55
+ const plugins: Plugin[] = [
56
+ {
57
+ name: 'vite-plugin-svelte',
58
+ // make sure our resolver runs before vite internal resolver to resolve svelte field correctly
59
+ enforce: 'pre',
60
+ api,
61
+ async config(config, configEnv): Promise<Partial<UserConfig>> {
62
+ // setup logger
63
+ if (process.env.DEBUG) {
64
+ log.setLevel('debug');
65
+ } else if (config.logLevel) {
66
+ log.setLevel(config.logLevel);
67
+ }
68
+ // @ts-expect-error temporarily lend the options variable until fixed in configResolved
69
+ options = await preResolveOptions(inlineOptions, config, configEnv);
70
+ // extra vite config
71
+ const extraViteConfig = buildExtraViteConfig(options, config);
72
+ log.debug('additional vite config', extraViteConfig);
73
+ return extraViteConfig;
74
+ },
75
+
76
+ async configResolved(config) {
77
+ options = resolveOptions(options, config);
78
+ patchResolvedViteConfig(config, options);
79
+ requestParser = buildIdParser(options);
80
+ compileSvelte = createCompileSvelte(options);
81
+ viteConfig = config;
82
+ // TODO deep clone to avoid mutability from outside?
83
+ api.options = options;
84
+ log.debug('resolved options', options);
85
+ },
86
+
87
+ async buildStart() {
88
+ if (!options.experimental?.prebundleSvelteLibraries) return;
89
+ const isSvelteMetadataChanged = await saveSvelteMetadata(viteConfig.cacheDir, options);
90
+ if (isSvelteMetadataChanged) {
91
+ // Force Vite to optimize again. Although we mutate the config here, it works because
92
+ // Vite's optimizer runs after `buildStart()`.
93
+ // TODO: verify this works in vite3
94
+ viteConfig.optimizeDeps.force = true;
95
+ }
96
+ },
97
+
98
+ configureServer(server) {
99
+ // eslint-disable-next-line no-unused-vars
100
+ options.server = server;
101
+ setupWatchers(options, cache, requestParser);
102
+ },
103
+
104
+ load(id, opts) {
105
+ const ssr = !!opts?.ssr;
106
+ const svelteRequest = requestParser(id, !!ssr);
107
+ if (svelteRequest) {
108
+ const { filename, query } = svelteRequest;
109
+ // virtual css module
110
+ if (query.svelte && query.type === 'style') {
111
+ const css = cache.getCSS(svelteRequest);
112
+ if (css) {
113
+ log.debug(`load returns css for ${filename}`);
114
+ return css;
115
+ }
116
+ }
117
+ // prevent vite asset plugin from loading files as url that should be compiled in transform
118
+ if (viteConfig.assetsInclude(filename)) {
119
+ log.debug(`load returns raw content for ${filename}`);
120
+ return fs.readFileSync(filename, 'utf-8');
121
+ }
122
+ }
123
+ },
124
+
125
+ async resolveId(importee, importer, opts) {
126
+ const ssr = !!opts?.ssr;
127
+ const svelteRequest = requestParser(importee, ssr);
128
+ if (svelteRequest?.query.svelte) {
129
+ if (svelteRequest.query.type === 'style') {
130
+ // return cssId with root prefix so postcss pipeline of vite finds the directory correctly
131
+ // see https://github.com/sveltejs/vite-plugin-svelte/issues/14
132
+ log.debug(`resolveId resolved virtual css module ${svelteRequest.cssId}`);
133
+ return svelteRequest.cssId;
134
+ }
135
+ log.debug(`resolveId resolved ${importee}`);
136
+ return importee; // query with svelte tag, an id we generated, no need for further analysis
137
+ }
138
+
139
+ if (ssr && importee === 'svelte') {
140
+ if (!resolvedSvelteSSR) {
141
+ resolvedSvelteSSR = this.resolve('svelte/ssr', undefined, { skipSelf: true }).then(
142
+ (svelteSSR) => {
143
+ log.debug('resolved svelte to svelte/ssr');
144
+ return svelteSSR;
145
+ },
146
+ (err) => {
147
+ log.debug(
148
+ 'failed to resolve svelte to svelte/ssr. Update svelte to a version that exports it',
149
+ err
150
+ );
151
+ return null; // returning null here leads to svelte getting resolved regularly
152
+ }
153
+ );
154
+ }
155
+ return resolvedSvelteSSR;
156
+ }
157
+ try {
158
+ const resolved = resolveViaPackageJsonSvelte(importee, importer, cache);
159
+ if (resolved) {
160
+ log.debug(
161
+ `resolveId resolved ${resolved} via package.json svelte field of ${importee}`
162
+ );
163
+ return resolved;
164
+ }
165
+ } catch (e) {
166
+ log.debug.once(
167
+ `error trying to resolve ${importee} from ${importer} via package.json svelte field `,
168
+ e
169
+ );
170
+ // this error most likely happens due to non-svelte related importee/importers so swallow it here
171
+ // in case it really way a svelte library, users will notice anyway. (lib not working due to failed resolve)
172
+ }
173
+ },
174
+
175
+ async transform(code, id, opts) {
176
+ const ssr = !!opts?.ssr;
177
+ const svelteRequest = requestParser(id, ssr);
178
+ if (!svelteRequest || svelteRequest.query.svelte) {
179
+ return;
180
+ }
181
+ let compileData;
182
+ try {
183
+ compileData = await compileSvelte(svelteRequest, code, options);
184
+ } catch (e) {
185
+ cache.setError(svelteRequest, e);
186
+ throw toRollupError(e, options);
187
+ }
188
+ logCompilerWarnings(svelteRequest, compileData.compiled.warnings, options);
189
+ cache.update(compileData);
190
+ if (compileData.dependencies?.length && options.server) {
191
+ compileData.dependencies.forEach((d) => {
192
+ ensureWatchedFile(options.server!.watcher, d, options.root);
193
+ });
194
+ }
195
+ log.debug(`transform returns compiled js for ${svelteRequest.filename}`);
196
+ return {
197
+ ...compileData.compiled.js,
198
+ meta: {
199
+ vite: {
200
+ lang: compileData.lang
201
+ }
202
+ }
203
+ };
204
+ },
205
+
206
+ handleHotUpdate(ctx: HmrContext): void | Promise<Array<ModuleNode> | void> {
207
+ if (!options.hot || !options.emitCss) {
208
+ return;
209
+ }
210
+ const svelteRequest = requestParser(ctx.file, false, ctx.timestamp);
211
+ if (svelteRequest) {
212
+ try {
213
+ return handleHotUpdate(compileSvelte, ctx, svelteRequest, cache, options);
214
+ } catch (e) {
215
+ throw toRollupError(e, options);
216
+ }
217
+ }
218
+ }
219
+ }
220
+ ];
221
+ plugins.push(svelteInspector());
222
+ return plugins.filter(Boolean);
223
+ }
224
+
225
+ export { loadSvelteConfig } from './utils/load-svelte-config';
226
+
227
+ export {
228
+ Options,
229
+ PluginOptions,
230
+ SvelteOptions,
231
+ Preprocessor,
232
+ PreprocessorGroup,
233
+ CompileOptions,
234
+ CssHashGetter,
235
+ Arrayable,
236
+ MarkupPreprocessor,
237
+ ModuleFormat,
238
+ Processed,
239
+ Warning
240
+ } from './utils/options';
241
+
242
+ export { SvelteWarningsMessage } from './utils/log';
@@ -0,0 +1,245 @@
1
+ <script>
2
+ // do not use TS here so that this component works in non-ts projects too
3
+ import { onMount } from 'svelte';
4
+ // eslint-disable-next-line node/no-missing-import
5
+ import options from 'virtual:svelte-inspector-options';
6
+ const toggle_combo = options.toggleKeyCombo?.toLowerCase().split('-');
7
+
8
+ let enabled = false;
9
+
10
+ const icon = `data:image/svg+xml;base64,${btoa(
11
+ `
12
+ <svg xmlns="http://www.w3.org/2000/svg" width="21" height="25" viewBox="0 0 107 128">
13
+ <title>svelte-inspector-logo</title>
14
+ <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"/>
15
+ <polygon points="0,0 15,40 40,20" stroke="#ff3e00" fill="#ff3e00"></polygon>
16
+ </svg>
17
+ `
18
+ .replace(/[\n\r\t\s]+/g, ' ')
19
+ .trim()
20
+ )}`;
21
+
22
+ // location of code in file
23
+ let file_loc;
24
+ // cursor pos and width for file_loc overlay positioning
25
+ let x, y, w;
26
+
27
+ let active_el;
28
+ let toggle_el;
29
+
30
+ let enabled_ts;
31
+
32
+ $: show_toggle =
33
+ options.showToggleButton === 'always' || (options.showToggleButton === 'active' && enabled);
34
+
35
+ function mousemove(event) {
36
+ x = event.x;
37
+ y = event.y;
38
+ }
39
+
40
+ function findMetaEl(el) {
41
+ while (el) {
42
+ const file = el.__svelte_meta?.loc?.file;
43
+ if (el !== toggle_el && file && !file.includes('node_modules/')) {
44
+ return el;
45
+ }
46
+ el = el.parentNode;
47
+ }
48
+ }
49
+
50
+ function mouseover(event) {
51
+ const el = findMetaEl(event.target);
52
+ if (options.customStyles && el !== active_el) {
53
+ if (active_el) {
54
+ active_el.classList.remove('svelte-inspector-active-target');
55
+ }
56
+ if (el) {
57
+ el.classList.add('svelte-inspector-active-target');
58
+ }
59
+ }
60
+ if (el) {
61
+ const { file, line, column } = el.__svelte_meta.loc;
62
+ file_loc = `${file}:${line + 1}:${column + 1}`;
63
+ } else {
64
+ file_loc = null;
65
+ }
66
+ active_el = el;
67
+ }
68
+
69
+ function click(event) {
70
+ if (file_loc) {
71
+ event.preventDefault();
72
+ event.stopPropagation();
73
+ event.stopImmediatePropagation();
74
+ fetch(`/__open-in-editor?file=${encodeURIComponent(file_loc)}`);
75
+ if (options.holdMode && is_holding()) {
76
+ disable();
77
+ }
78
+ }
79
+ }
80
+
81
+ function is_key_active(key, event) {
82
+ switch (key) {
83
+ case 'shift':
84
+ case 'control':
85
+ case 'alt':
86
+ case 'meta':
87
+ return event.getModifierState(key.charAt(0).toUpperCase() + key.slice(1));
88
+ default:
89
+ return key === event.key.toLowerCase();
90
+ }
91
+ }
92
+
93
+ function is_combo(event) {
94
+ return toggle_combo?.every((key) => is_key_active(key, event));
95
+ }
96
+
97
+ function is_holding() {
98
+ return enabled_ts && Date.now() - enabled_ts > 250;
99
+ }
100
+
101
+ function keydown(event) {
102
+ if (event.repeat || event.key === undefined) {
103
+ return;
104
+ }
105
+
106
+ if (is_combo(event)) {
107
+ toggle();
108
+ if (options.holdMode && enabled) {
109
+ enabled_ts = Date.now();
110
+ }
111
+ }
112
+ }
113
+
114
+ function keyup(event) {
115
+ if (event.repeat) {
116
+ return;
117
+ }
118
+ const k = event.key.toLowerCase();
119
+ if (enabled && is_holding() && toggle_combo.includes(k)) {
120
+ disable();
121
+ } else {
122
+ enabled_ts = null;
123
+ }
124
+ }
125
+
126
+ function toggle() {
127
+ enabled ? disable() : enable();
128
+ }
129
+
130
+ function listeners(body, enabled) {
131
+ const l = enabled ? body.addEventListener : body.removeEventListener;
132
+ l('mousemove', mousemove);
133
+ l('mouseover', mouseover);
134
+ l('click', click, true);
135
+ }
136
+
137
+ function enable() {
138
+ enabled = true;
139
+ const b = document.body;
140
+ if (options.customStyles) {
141
+ b.classList.add('svelte-inspector-enabled');
142
+ }
143
+ listeners(b, enabled);
144
+ }
145
+
146
+ function disable() {
147
+ enabled = false;
148
+ enabled_ts = null;
149
+ const b = document.body;
150
+ listeners(b, enabled);
151
+ if (options.customStyles) {
152
+ b.classList.remove('svelte-inspector-enabled');
153
+ active_el?.classList.remove('svelte-inspector-active-target');
154
+ }
155
+ active_el = null;
156
+ }
157
+
158
+ onMount(() => {
159
+ const s = document.createElement('style');
160
+ s.setAttribute('type', 'text/css');
161
+ s.setAttribute('id', 'svelte-inspector-style');
162
+ s.textContent = `:root { --svelte-inspector-icon: url(${icon})};`;
163
+ document.head.append(s);
164
+ if (toggle_combo) {
165
+ document.body.addEventListener('keydown', keydown);
166
+ if (options.holdMode) {
167
+ document.body.addEventListener('keyup', keyup);
168
+ }
169
+ }
170
+ return () => {
171
+ // make sure we get rid of everything
172
+ disable();
173
+ const s = document.head.querySelector('#svelte-inspector-style');
174
+ if (s) {
175
+ document.head.removeChild(s);
176
+ }
177
+ if (toggle_combo) {
178
+ document.body.removeEventListener('keydown', keydown);
179
+ if (options.holdMode) {
180
+ document.body.addEventListener('keyup', keyup);
181
+ }
182
+ }
183
+ };
184
+ });
185
+ </script>
186
+
187
+ {#if show_toggle}
188
+ <div
189
+ class="svelte-inspector-toggle"
190
+ class:enabled
191
+ style={`background-image: var(--svelte-inspector-icon);${options.toggleButtonPos
192
+ .split('-')
193
+ .map((p) => `${p}: 8px;`)
194
+ .join('')}`}
195
+ on:click={() => toggle()}
196
+ bind:this={toggle_el}
197
+ />
198
+ {/if}
199
+ {#if enabled && file_loc}
200
+ <div
201
+ class="svelte-inspector-overlay"
202
+ style:left="{Math.min(x + 3, document.body.clientWidth - w - 10)}px"
203
+ style:top="{y + 30}px"
204
+ bind:offsetWidth={w}
205
+ >
206
+ {file_loc}
207
+ </div>
208
+ {/if}
209
+
210
+ <style>
211
+ :global(body.svelte-inspector-enabled *) {
212
+ cursor: var(--svelte-inspector-icon), crosshair !important;
213
+ }
214
+ :global(.svelte-inspector-active-target) {
215
+ outline: 2px dashed #ff3e00 !important;
216
+ }
217
+
218
+ .svelte-inspector-overlay {
219
+ position: fixed;
220
+ background-color: rgba(0, 0, 0, 0.8);
221
+ color: #fff;
222
+ padding: 2px 4px;
223
+ border-radius: 5px;
224
+ z-index: 999999;
225
+ }
226
+
227
+ .svelte-inspector-toggle {
228
+ border: 1px solid #ff3e00;
229
+ border-radius: 8px;
230
+ position: fixed;
231
+ height: 32px;
232
+ width: 32px;
233
+ background-color: white;
234
+ background-position: center;
235
+ background-repeat: no-repeat;
236
+ cursor: pointer;
237
+ }
238
+
239
+ .svelte-inspector-toggle:not(.enabled) {
240
+ filter: grayscale(1);
241
+ }
242
+ .svelte-inspector-toggle:hover {
243
+ background-color: #facece;
244
+ }
245
+ </style>
@@ -0,0 +1,15 @@
1
+ // eslint-disable-next-line node/no-missing-import
2
+ import Inspector from 'virtual:svelte-inspector-path:Inspector.svelte';
3
+
4
+ function create_inspector_host() {
5
+ const id = 'svelte-inspector-host';
6
+ if (document.getElementById(id) != null) {
7
+ throw new Error('svelte-inspector-host element already exists');
8
+ }
9
+ const el = document.createElement('div');
10
+ el.setAttribute('id', id);
11
+ document.getElementsByTagName('body')[0].appendChild(el);
12
+ return el;
13
+ }
14
+
15
+ new Inspector({ target: create_inspector_host() });
@@ -0,0 +1,106 @@
1
+ import { Plugin, normalizePath } from 'vite';
2
+ import { log } from '../../utils/log';
3
+ import { InspectorOptions } from '../../utils/options';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import fs from 'fs';
7
+
8
+ const defaultInspectorOptions: InspectorOptions = {
9
+ toggleKeyCombo: process.platform === 'win32' ? 'control-shift' : 'meta-shift',
10
+ holdMode: false,
11
+ showToggleButton: 'active',
12
+ toggleButtonPos: 'top-right',
13
+ customStyles: true
14
+ };
15
+
16
+ function getInspectorPath() {
17
+ const pluginPath = normalizePath(path.dirname(fileURLToPath(import.meta.url)));
18
+ return pluginPath.replace(/\/vite-plugin-svelte\/dist$/, '/vite-plugin-svelte/src/ui/inspector/');
19
+ }
20
+
21
+ export function svelteInspector(): Plugin {
22
+ const inspectorPath = getInspectorPath();
23
+ log.debug.enabled && log.debug(`svelte inspector path: ${inspectorPath}`);
24
+ let inspectorOptions: InspectorOptions;
25
+ let appendTo: string | undefined;
26
+ let disabled = false;
27
+
28
+ return {
29
+ name: 'vite-plugin-svelte:inspector',
30
+ apply: 'serve',
31
+ enforce: 'pre',
32
+
33
+ configResolved(config) {
34
+ const vps = config.plugins.find((p) => p.name === 'vite-plugin-svelte');
35
+ if (vps?.api?.options?.experimental?.inspector) {
36
+ inspectorOptions = {
37
+ ...defaultInspectorOptions,
38
+ ...vps.api.options.experimental.inspector
39
+ };
40
+ }
41
+ if (!vps || !inspectorOptions) {
42
+ log.debug('inspector disabled, could not find config');
43
+ disabled = true;
44
+ } else {
45
+ if (vps.api.options.kit && !inspectorOptions.appendTo) {
46
+ const out_dir = path.basename(vps.api.options.kit.outDir || '.svelte-kit');
47
+ inspectorOptions.appendTo = `${out_dir}/generated/root.svelte`;
48
+ }
49
+ appendTo = inspectorOptions.appendTo;
50
+ }
51
+ },
52
+
53
+ async resolveId(importee: string, importer, options) {
54
+ if (options?.ssr || disabled) {
55
+ return;
56
+ }
57
+ if (importee.startsWith('virtual:svelte-inspector-options')) {
58
+ return importee;
59
+ } else if (importee.startsWith('virtual:svelte-inspector-path:')) {
60
+ const resolved = importee.replace('virtual:svelte-inspector-path:', inspectorPath);
61
+ log.debug.enabled && log.debug(`resolved ${importee} with ${resolved}`);
62
+ return resolved;
63
+ }
64
+ },
65
+
66
+ async load(id, options) {
67
+ if (options?.ssr || disabled) {
68
+ return;
69
+ }
70
+ if (id === 'virtual:svelte-inspector-options') {
71
+ return `export default ${JSON.stringify(inspectorOptions ?? {})}`;
72
+ } else if (id.startsWith(inspectorPath)) {
73
+ // read file ourselves to avoid getting shut out by vites fs.allow check
74
+ return await fs.promises.readFile(id, 'utf-8');
75
+ }
76
+ },
77
+
78
+ transform(code: string, id: string, options?: { ssr?: boolean }) {
79
+ if (options?.ssr || disabled || !appendTo) {
80
+ return;
81
+ }
82
+ if (id.endsWith(appendTo)) {
83
+ return { code: `${code}\nimport 'virtual:svelte-inspector-path:load-inspector.js'` };
84
+ }
85
+ },
86
+ transformIndexHtml(html) {
87
+ if (disabled || appendTo) {
88
+ return;
89
+ }
90
+ return {
91
+ html,
92
+ tags: [
93
+ {
94
+ tag: 'script',
95
+ injectTo: 'body',
96
+ attrs: {
97
+ type: 'module',
98
+ // /@id/ is needed, otherwise the virtual: is seen as protocol by browser and cors error happens
99
+ src: '/@id/virtual:svelte-inspector-path:load-inspector.js'
100
+ }
101
+ }
102
+ ]
103
+ };
104
+ }
105
+ };
106
+ }
@@ -0,0 +1,43 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { findRootSvelteDependencies, needsOptimization } from '../dependencies';
3
+ import * as path from 'path';
4
+ import { createRequire } from 'module';
5
+ import { fileURLToPath } from 'url';
6
+ const __dir = path.dirname(fileURLToPath(import.meta.url));
7
+ const e2eTestRoot = path.resolve(__dir, '../../../../../packages/e2e-tests');
8
+
9
+ describe('dependencies', () => {
10
+ describe('findRootSvelteDependencies', () => {
11
+ it('should find svelte dependencies in packages/e2e-test/hmr', () => {
12
+ const deps = findRootSvelteDependencies(path.resolve('packages/e2e-tests/hmr'));
13
+ expect(deps).toHaveLength(1);
14
+ expect(deps[0].name).toBe('e2e-test-dep-svelte-simple');
15
+ expect(deps[0].path).toEqual([]);
16
+ });
17
+ it('should find nested svelte dependencies in packages/e2e-test/package-json-svelte-field', () => {
18
+ const deps = findRootSvelteDependencies(path.join(e2eTestRoot, 'package-json-svelte-field'));
19
+ expect(deps).toHaveLength(3);
20
+ const hybrid = deps.find((dep) => dep.name === 'e2e-test-dep-svelte-hybrid');
21
+ expect(hybrid).toBeTruthy();
22
+ expect(hybrid.path).toHaveLength(0);
23
+ const nested = deps.find((dep) => dep.name === 'e2e-test-dep-svelte-nested');
24
+ expect(nested).toBeTruthy();
25
+ expect(nested.path).toHaveLength(0);
26
+ const simple = deps.find((dep) => dep.name === 'e2e-test-dep-svelte-simple');
27
+ expect(simple).toBeTruthy();
28
+ expect(simple.path).toHaveLength(1);
29
+ expect(simple.path[0]).toBe('e2e-test-dep-svelte-nested');
30
+ });
31
+ });
32
+ describe('needsOptimization', () => {
33
+ it('should optimize cjs deps only', () => {
34
+ const testDepsPath = path.join(e2eTestRoot, 'dependencies/package.json');
35
+ const localRequire = createRequire(testDepsPath);
36
+ expect(needsOptimization('e2e-test-dep-cjs-and-esm', localRequire)).toBe(false);
37
+ expect(needsOptimization('e2e-test-dep-cjs-only', localRequire)).toBe(true);
38
+ expect(needsOptimization('e2e-test-dep-esm-only', localRequire)).toBe(false);
39
+ expect(needsOptimization('e2e-test-dep-index-only', localRequire)).toBe(true);
40
+ expect(needsOptimization('e2e-test-dep-types-only', localRequire)).toBe(false);
41
+ });
42
+ });
43
+ });
@@ -0,0 +1,25 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { buildMagicString, buildSourceMap } from '../sourcemap';
3
+
4
+ describe('sourcemap', () => {
5
+ describe('buildMagicString', () => {
6
+ it('should return a valid magic string', async () => {
7
+ const from = 'h1{color: blue}\nh2{color: green}\nh3{color: red}\n';
8
+ const to = 'h1{color: blue}\ndiv{color: white}\nh3{color: red}\nh2{color: green}\n';
9
+ const m = await buildMagicString(from, to);
10
+ expect(m).toBeDefined();
11
+ expect(m.original).toBe(from);
12
+ expect(m.toString()).toBe(to);
13
+ });
14
+ });
15
+ describe('buildSourceMap', () => {
16
+ it('should return a map with mappings and filename', async () => {
17
+ const map = await buildSourceMap('foo', 'bar', 'foo.txt');
18
+ expect(map).toBeDefined();
19
+ expect(map.mappings).toBeDefined();
20
+ expect(map.mappings[0]).toBeDefined();
21
+ expect(map.mappings[0][0]).toBeDefined();
22
+ expect(map.sources[0]).toBe('foo.txt');
23
+ });
24
+ });
25
+ });