@sveltejs/vite-plugin-svelte 1.0.0-next.42 → 1.0.0-next.43

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.
@@ -0,0 +1,101 @@
1
+ import { createRequire } from 'module';
2
+ import { Plugin } from 'vite';
3
+ import { log } from '../../utils/log';
4
+ import { InspectorOptions } from '../../utils/options';
5
+
6
+ const defaultInspectorOptions: InspectorOptions = {
7
+ toggleKeyCombo: process.platform === 'win32' ? 'control-shift' : 'meta-shift',
8
+ holdMode: false,
9
+ showToggleButton: 'active',
10
+ toggleButtonPos: 'top-right',
11
+ customStyles: true
12
+ };
13
+
14
+ export function svelteInspector(): Plugin {
15
+ let root: string;
16
+ let rootRequire: NodeRequire;
17
+ let inspectorOptions: InspectorOptions;
18
+ let append_to: string | undefined;
19
+
20
+ return {
21
+ name: 'vite-plugin-svelte:inspector',
22
+ apply: 'serve',
23
+ enforce: 'pre',
24
+
25
+ configResolved(config) {
26
+ const vps = config.plugins.find((p) => p.name === 'vite-plugin-svelte');
27
+ if (vps?.api?.options?.experimental?.inspector) {
28
+ inspectorOptions = {
29
+ ...defaultInspectorOptions,
30
+ ...vps.api.options.experimental.inspector
31
+ };
32
+ }
33
+ if (!vps || !inspectorOptions) {
34
+ // disabled, turn all hooks into noops
35
+ this.resolveId = this.load = this.transformIndexHtml = this.transform = () => {};
36
+ } else {
37
+ root = config.root || process.cwd();
38
+ rootRequire = createRequire(root);
39
+ if (vps.api.options.kit && !inspectorOptions.appendTo) {
40
+ const out_dir = vps.api.options.kit.outDir || '.svelte-kit';
41
+ inspectorOptions.appendTo = `${out_dir}/runtime/client/start.js`;
42
+ }
43
+ append_to = inspectorOptions.appendTo;
44
+ }
45
+ },
46
+
47
+ async resolveId(importee: string, importer, options) {
48
+ if (options?.ssr) {
49
+ return;
50
+ }
51
+ if (importee === 'virtual:svelte-inspector-options') {
52
+ return importee;
53
+ }
54
+ if (importee.startsWith('virtual:svelte-inspector:')) {
55
+ // this is needed because the plugin itself is not a dependency of the app so regular resolve may not find it
56
+ const file = importee.replace(
57
+ 'virtual:svelte-inspector:',
58
+ '@sveltejs/vite-plugin-svelte/src/ui/inspector/'
59
+ );
60
+ const path = rootRequire.resolve(file);
61
+ if (path) {
62
+ return path;
63
+ } else {
64
+ log.error.once(`failed to resolve ${file} for ${importee} from ${root}`);
65
+ }
66
+ }
67
+ },
68
+ load(id) {
69
+ if (id === 'virtual:svelte-inspector-options') {
70
+ return `export default ${JSON.stringify(inspectorOptions ?? {})}`;
71
+ }
72
+ },
73
+ transform(code: string, id: string, options?: { ssr?: boolean }) {
74
+ if (options?.ssr || !append_to) {
75
+ return;
76
+ }
77
+ if (id.endsWith(append_to)) {
78
+ return { code: `${code}\nimport 'virtual:svelte-inspector:load-inspector.ts'` };
79
+ }
80
+ },
81
+ transformIndexHtml(html) {
82
+ if (append_to) {
83
+ return;
84
+ }
85
+ return {
86
+ html,
87
+ tags: [
88
+ {
89
+ tag: 'script',
90
+ injectTo: 'body',
91
+ attrs: {
92
+ type: 'module',
93
+ // /@id/ is needed, otherwise the virtual: is seen as protocol by browser and cors error happens
94
+ src: '/@id/virtual:svelte-inspector:load-inspector.ts'
95
+ }
96
+ }
97
+ ]
98
+ };
99
+ }
100
+ };
101
+ }
@@ -6,6 +6,8 @@ import { SvelteRequest } from './id';
6
6
  import { safeBase64Hash } from './hash';
7
7
  import { log } from './log';
8
8
 
9
+ const scriptLangRE = /<script [^>]*lang=["']?([^"' >]+)["']?[^>]*>/;
10
+
9
11
  const _createCompileSvelte = (makeHot: Function) =>
10
12
  async function compileSvelte(
11
13
  svelteRequest: SvelteRequest,
@@ -88,6 +90,7 @@ const _createCompileSvelte = (makeHot: Function) =>
88
90
  return {
89
91
  filename,
90
92
  normalizedFilename,
93
+ lang: code.match(scriptLangRE)?.[1] || 'js',
91
94
  // @ts-ignore
92
95
  compiled,
93
96
  ssr,
@@ -148,6 +151,7 @@ export interface Compiled {
148
151
  export interface CompileData {
149
152
  filename: string;
150
153
  normalizedFilename: string;
154
+ lang: string;
151
155
  compiled: Compiled;
152
156
  ssr: boolean | undefined;
153
157
  dependencies: string[];
@@ -24,6 +24,7 @@ import { findRootSvelteDependencies, needsOptimization, SvelteDependency } from
24
24
  import { createRequire } from 'module';
25
25
  import { esbuildSveltePlugin, facadeEsbuildSveltePluginName } from './esbuild';
26
26
  import { addExtraPreprocessors } from './preprocess';
27
+ import deepmerge from 'deepmerge';
27
28
 
28
29
  const knownOptions = new Set([
29
30
  'configFile',
@@ -37,7 +38,8 @@ const knownOptions = new Set([
37
38
  'hot',
38
39
  'ignorePluginPreprocessors',
39
40
  'disableDependencyReinclusion',
40
- 'experimental'
41
+ 'experimental',
42
+ 'kit'
41
43
  ]);
42
44
 
43
45
  export function validateInlineOptions(inlineOptions?: Partial<Options>) {
@@ -65,26 +67,19 @@ export async function preResolveOptions(
65
67
  }
66
68
  };
67
69
  const svelteConfig = await loadSvelteConfig(viteConfigWithResolvedRoot, inlineOptions);
68
- const merged = {
69
- ...defaultOptions,
70
- ...svelteConfig,
71
- ...inlineOptions,
72
- compilerOptions: {
73
- ...defaultOptions?.compilerOptions,
74
- ...svelteConfig?.compilerOptions,
75
- ...inlineOptions?.compilerOptions
76
- },
77
- experimental: {
78
- ...defaultOptions?.experimental,
79
- ...svelteConfig?.experimental,
80
- ...inlineOptions?.experimental
81
- },
82
- // extras
70
+ const extraOptions: Partial<PreResolvedOptions> = {
83
71
  root: viteConfigWithResolvedRoot.root!,
84
72
  isBuild: viteEnv.command === 'build',
85
73
  isServe: viteEnv.command === 'serve',
86
74
  isDebug: process.env.DEBUG != null
87
75
  };
76
+ const merged = mergeConfigs<Partial<PreResolvedOptions> | undefined>(
77
+ defaultOptions,
78
+ svelteConfig,
79
+ inlineOptions,
80
+ extraOptions
81
+ );
82
+
88
83
  // configFile of svelteConfig contains the absolute path it was loaded from,
89
84
  // prefer it over the possibly relative inline path
90
85
  if (svelteConfig?.configFile) {
@@ -93,6 +88,17 @@ export async function preResolveOptions(
93
88
  return merged;
94
89
  }
95
90
 
91
+ function mergeConfigs<T>(...configs: T[]): ResolvedOptions {
92
+ let result = {};
93
+ for (const config of configs.filter(Boolean)) {
94
+ result = deepmerge<T>(result, config, {
95
+ // replace arrays
96
+ arrayMerge: (target: any[], source: any[]) => source ?? target
97
+ });
98
+ }
99
+ return result as ResolvedOptions;
100
+ }
101
+
96
102
  // used in configResolved phase, merges a contextual default config, pre-resolved options, and some preprocessors.
97
103
  // also validates the final config.
98
104
  export function resolveOptions(
@@ -106,16 +112,12 @@ export function resolveOptions(
106
112
  dev: !viteConfig.isProduction
107
113
  }
108
114
  };
109
- const merged: ResolvedOptions = {
110
- ...defaultOptions,
111
- ...preResolveOptions,
112
- compilerOptions: {
113
- ...defaultOptions.compilerOptions,
114
- ...preResolveOptions.compilerOptions
115
- },
115
+ const extraOptions: Partial<ResolvedOptions> = {
116
116
  root: viteConfig.root,
117
117
  isProduction: viteConfig.isProduction
118
118
  };
119
+ const merged: ResolvedOptions = mergeConfigs(defaultOptions, preResolveOptions, extraOptions);
120
+
119
121
  addExtraPreprocessors(merged, viteConfig);
120
122
  enforceOptionsForHmr(merged);
121
123
  enforceOptionsForProduction(merged);
@@ -207,7 +209,7 @@ export function buildExtraViteConfig(
207
209
  );
208
210
  }
209
211
 
210
- if (options.experimental.prebundleSvelteLibraries) {
212
+ if (options.experimental?.prebundleSvelteLibraries) {
211
213
  extraViteConfig.optimizeDeps = {
212
214
  ...extraViteConfig.optimizeDeps,
213
215
  // Experimental Vite API to allow these extensions to be scanned and prebundled
@@ -256,7 +258,7 @@ function buildOptimizeDepsForSvelte(
256
258
  }
257
259
 
258
260
  // If we prebundle svelte libraries, we can skip the whole prebundling dance below
259
- if (options.experimental.prebundleSvelteLibraries) {
261
+ if (options.experimental?.prebundleSvelteLibraries) {
260
262
  return { include, exclude };
261
263
  }
262
264
 
@@ -355,7 +357,7 @@ export interface Options {
355
357
  /**
356
358
  * Path to a svelte config file, either absolute or relative to Vite root
357
359
  *
358
- * set to `false` to skip reading config from a file
360
+ * set to `false` to ignore the svelte config file
359
361
  *
360
362
  * @see https://vitejs.dev/config/#root
361
363
  */
@@ -509,6 +511,55 @@ export interface ExperimentalOptions {
509
511
  code: string;
510
512
  compileOptions: Partial<CompileOptions>;
511
513
  }) => Promise<Partial<CompileOptions> | void> | Partial<CompileOptions> | void;
514
+
515
+ /**
516
+ * enable svelte inspector
517
+ */
518
+ inspector?: InspectorOptions | boolean;
519
+ }
520
+
521
+ export interface InspectorOptions {
522
+ /**
523
+ * define a key combo to toggle inspector,
524
+ * @default 'control-shift' on windows, 'meta-shift' on other os
525
+ *
526
+ * any number of modifiers `control` `shift` `alt` `meta` followed by zero or one regular key, separated by -
527
+ * examples: control-shift, control-o, control-alt-s meta-x control-meta
528
+ * Some keys have native behavior (e.g. alt-s opens history menu on firefox).
529
+ * To avoid conflicts or accidentally typing into inputs, modifier only combinations are recommended.
530
+ */
531
+ toggleKeyCombo?: string;
532
+
533
+ /**
534
+ * inspector is automatically disabled when releasing toggleKeyCombo after holding it for a longpress
535
+ * @default false
536
+ */
537
+ holdMode?: boolean;
538
+ /**
539
+ * when to show the toggle button
540
+ * @default 'active'
541
+ */
542
+ showToggleButton?: 'always' | 'active' | 'never';
543
+
544
+ /**
545
+ * where to display the toggle button
546
+ * @default top-right
547
+ */
548
+ toggleButtonPos?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
549
+
550
+ /**
551
+ * inject custom styles when inspector is active
552
+ */
553
+ customStyles?: boolean;
554
+
555
+ /**
556
+ * append an import to the module id ending with `appendTo` instead of adding a script into body
557
+ * useful for frameworks that do not support trannsformIndexHtml hook
558
+ *
559
+ * WARNING: only set this if you know exactly what it does.
560
+ * Regular users of vite-plugin-svelte or SvelteKit do not need it
561
+ */
562
+ appendTo?: string;
512
563
  }
513
564
 
514
565
  export interface PreResolvedOptions extends Options {
@@ -58,30 +58,34 @@ export function setupWatchers(
58
58
  }
59
59
  };
60
60
 
61
- const possibleSvelteConfigs = knownSvelteConfigNames.map((cfg) => path.join(root, cfg));
62
- const restartOnConfigAdd = (filename: string) => {
63
- if (possibleSvelteConfigs.includes(filename)) {
64
- triggerViteRestart(filename);
65
- }
66
- };
67
-
68
- const restartOnConfigChange = (filename: string) => {
69
- if (filename === svelteConfigFile) {
70
- triggerViteRestart(filename);
71
- }
72
- };
73
-
74
61
  // collection of watcher listeners by event
75
62
  const listenerCollection = {
76
63
  add: [] as Array<Function>,
77
64
  change: [emitChangeEventOnDependants],
78
65
  unlink: [removeUnlinkedFromCache, emitChangeEventOnDependants]
79
66
  };
80
- if (svelteConfigFile) {
81
- listenerCollection.change.push(restartOnConfigChange);
82
- listenerCollection.unlink.push(restartOnConfigChange);
83
- } else {
84
- listenerCollection.add.push(restartOnConfigAdd);
67
+
68
+ if (svelteConfigFile !== false) {
69
+ // configFile false means we ignore the file and external process is responsible
70
+ const possibleSvelteConfigs = knownSvelteConfigNames.map((cfg) => path.join(root, cfg));
71
+ const restartOnConfigAdd = (filename: string) => {
72
+ if (possibleSvelteConfigs.includes(filename)) {
73
+ triggerViteRestart(filename);
74
+ }
75
+ };
76
+
77
+ const restartOnConfigChange = (filename: string) => {
78
+ if (filename === svelteConfigFile) {
79
+ triggerViteRestart(filename);
80
+ }
81
+ };
82
+
83
+ if (svelteConfigFile) {
84
+ listenerCollection.change.push(restartOnConfigChange);
85
+ listenerCollection.unlink.push(restartOnConfigChange);
86
+ } else {
87
+ listenerCollection.add.push(restartOnConfigAdd);
88
+ }
85
89
  }
86
90
 
87
91
  Object.entries(listenerCollection).forEach(([evt, listeners]) => {