@rsvelte/vite-plugin-svelte 0.1.0
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/LICENSE +21 -0
- package/README.md +28 -0
- package/package.json +59 -0
- package/src/index.js +42 -0
- package/src/plugins/compile-module.js +130 -0
- package/src/plugins/compile.js +65 -0
- package/src/plugins/configure.js +97 -0
- package/src/plugins/hot-update.js +196 -0
- package/src/plugins/load-compiled-css.js +66 -0
- package/src/plugins/load-custom.js +42 -0
- package/src/plugins/preprocess.js +208 -0
- package/src/plugins/setup-optimizer.js +340 -0
- package/src/preprocess.js +166 -0
- package/src/public.d.ts +217 -0
- package/src/types/compile.d.ts +37 -0
- package/src/types/id.d.ts +46 -0
- package/src/types/log.d.ts +24 -0
- package/src/types/options.d.ts +21 -0
- package/src/types/plugin-api.d.ts +15 -0
- package/src/types/vite-plugin-svelte-stats.d.ts +30 -0
- package/src/utils/compile.js +152 -0
- package/src/utils/constants.js +36 -0
- package/src/utils/dependencies.js +60 -0
- package/src/utils/error.js +167 -0
- package/src/utils/hash.js +43 -0
- package/src/utils/id.js +274 -0
- package/src/utils/load-svelte-config.js +80 -0
- package/src/utils/log.js +256 -0
- package/src/utils/options.js +618 -0
- package/src/utils/preprocess.js +89 -0
- package/src/utils/sourcemaps.js +82 -0
- package/src/utils/svelte-version.js +46 -0
- package/src/utils/vite-plugin-svelte-stats.js +248 -0
- package/src/utils/watch.js +95 -0
- package/types/index.d.ts +228 -0
- package/types/index.d.ts.map +31 -0
package/src/utils/id.js
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { normalizePath } from 'vite';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import process from 'node:process';
|
|
4
|
+
import { log } from './log.js';
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_SVELTE_EXT,
|
|
7
|
+
DEFAULT_SVELTE_MODULE_EXT,
|
|
8
|
+
DEFAULT_SVELTE_MODULE_INFIX,
|
|
9
|
+
SVELTE_VIRTUAL_STYLE_ID_REGEX
|
|
10
|
+
} from './constants.js';
|
|
11
|
+
import { arraify } from './options.js';
|
|
12
|
+
|
|
13
|
+
const VITE_FS_PREFIX = '/@fs/';
|
|
14
|
+
const IS_WINDOWS = process.platform === 'win32';
|
|
15
|
+
|
|
16
|
+
const SUPPORTED_COMPILER_OPTIONS = ['generate', 'dev', 'css', 'customElement', 'immutable'];
|
|
17
|
+
const TYPES_WITH_COMPILER_OPTIONS = ['style', 'script', 'all'];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {string} id
|
|
21
|
+
* @returns {{ filename: string, rawQuery: string }}
|
|
22
|
+
*/
|
|
23
|
+
function splitId(id) {
|
|
24
|
+
const parts = id.split('?', 2);
|
|
25
|
+
const filename = parts[0];
|
|
26
|
+
const rawQuery = parts[1];
|
|
27
|
+
return { filename, rawQuery };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {string} id
|
|
32
|
+
* @param {string} filename
|
|
33
|
+
* @param {string} rawQuery
|
|
34
|
+
* @param {string} root
|
|
35
|
+
* @param {number} timestamp
|
|
36
|
+
* @param {boolean} ssr
|
|
37
|
+
* @returns {import('../types/id.d.ts').SvelteRequest | undefined}
|
|
38
|
+
*/
|
|
39
|
+
function parseToSvelteRequest(id, filename, rawQuery, root, timestamp, ssr) {
|
|
40
|
+
const query = parseRequestQuery(rawQuery);
|
|
41
|
+
const rawOrDirect = !!(query.raw || query.direct);
|
|
42
|
+
if (query.url || (!query.svelte && rawOrDirect)) {
|
|
43
|
+
// skip requests with special vite tags
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const raw = rawOrDirect;
|
|
47
|
+
const normalizedFilename = normalize(filename, root);
|
|
48
|
+
const cssId = createVirtualImportId(filename, root, 'style');
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
id,
|
|
52
|
+
filename,
|
|
53
|
+
normalizedFilename,
|
|
54
|
+
cssId,
|
|
55
|
+
query,
|
|
56
|
+
timestamp,
|
|
57
|
+
ssr,
|
|
58
|
+
raw
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @param {string} filename
|
|
64
|
+
* @param {string} root
|
|
65
|
+
* @param {import('../types/id.d.ts').SvelteQueryTypes} type
|
|
66
|
+
* @returns {string}
|
|
67
|
+
*/
|
|
68
|
+
function createVirtualImportId(filename, root, type) {
|
|
69
|
+
const parts = ['svelte', `type=${type}`];
|
|
70
|
+
if (type === 'style') {
|
|
71
|
+
parts.push('lang.css');
|
|
72
|
+
}
|
|
73
|
+
if (existsInRoot(filename, root)) {
|
|
74
|
+
filename = root + filename;
|
|
75
|
+
} else if (filename.startsWith(VITE_FS_PREFIX)) {
|
|
76
|
+
filename = IS_WINDOWS
|
|
77
|
+
? filename.slice(VITE_FS_PREFIX.length) // remove /@fs/ from /@fs/C:/...
|
|
78
|
+
: filename.slice(VITE_FS_PREFIX.length - 1); // remove /@fs from /@fs/home/user
|
|
79
|
+
}
|
|
80
|
+
// return same virtual id format as vite-plugin-vue eg ...App.svelte?svelte&type=style&lang.css
|
|
81
|
+
return `${filename}?${parts.join('&')}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @param {string} rawQuery
|
|
86
|
+
* @returns {import('../types/id.d.ts').RequestQuery}
|
|
87
|
+
*/
|
|
88
|
+
function parseRequestQuery(rawQuery) {
|
|
89
|
+
const query = Object.fromEntries(new URLSearchParams(rawQuery));
|
|
90
|
+
for (const key in query) {
|
|
91
|
+
if (query[key] === '') {
|
|
92
|
+
// @ts-expect-error not boolean
|
|
93
|
+
query[key] = true;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const compilerOptions = query.compilerOptions;
|
|
97
|
+
if (compilerOptions) {
|
|
98
|
+
if (!((query.raw || query.direct) && TYPES_WITH_COMPILER_OPTIONS.includes(query.type))) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Invalid compilerOptions in query ${rawQuery}. CompilerOptions are only supported for raw or direct queries with type in "${TYPES_WITH_COMPILER_OPTIONS.join(
|
|
101
|
+
', '
|
|
102
|
+
)}" e.g. '?svelte&raw&type=script&compilerOptions={"generate":"server","dev":false}`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const parsed = JSON.parse(compilerOptions);
|
|
107
|
+
const invalid = Object.keys(parsed).filter(
|
|
108
|
+
(key) => !SUPPORTED_COMPILER_OPTIONS.includes(key)
|
|
109
|
+
);
|
|
110
|
+
if (invalid.length) {
|
|
111
|
+
throw new Error(
|
|
112
|
+
`Invalid compilerOptions in query ${rawQuery}: ${invalid.join(
|
|
113
|
+
', '
|
|
114
|
+
)}. Supported: ${SUPPORTED_COMPILER_OPTIONS.join(', ')}`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
query.compilerOptions = parsed;
|
|
118
|
+
} catch (e) {
|
|
119
|
+
log.error('failed to parse request query compilerOptions', e);
|
|
120
|
+
throw e;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return /** @type {import('../types/id.d.ts').RequestQuery}*/ query;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* posixify and remove root at start
|
|
129
|
+
*
|
|
130
|
+
* @param {string} filename
|
|
131
|
+
* @param {string} normalizedRoot
|
|
132
|
+
* @returns {string}
|
|
133
|
+
*/
|
|
134
|
+
export function normalize(filename, normalizedRoot) {
|
|
135
|
+
return stripRoot(normalizePath(filename), normalizedRoot);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* @param {string} filename
|
|
140
|
+
* @param {string} root
|
|
141
|
+
* @returns {boolean}
|
|
142
|
+
*/
|
|
143
|
+
function existsInRoot(filename, root) {
|
|
144
|
+
if (filename.startsWith(VITE_FS_PREFIX)) {
|
|
145
|
+
return false; // vite already tagged it as out of root
|
|
146
|
+
}
|
|
147
|
+
return fs.existsSync(root + filename);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @param {string} normalizedFilename
|
|
152
|
+
* @param {string} normalizedRoot
|
|
153
|
+
* @returns {string}
|
|
154
|
+
*/
|
|
155
|
+
function stripRoot(normalizedFilename, normalizedRoot) {
|
|
156
|
+
return normalizedFilename.startsWith(normalizedRoot + '/')
|
|
157
|
+
? normalizedFilename.slice(normalizedRoot.length)
|
|
158
|
+
: normalizedFilename;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
*
|
|
163
|
+
* @param {string} s
|
|
164
|
+
* @returns {string}
|
|
165
|
+
*/
|
|
166
|
+
function escapeRE(s) {
|
|
167
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @param {import('../types/options.d.ts').ResolvedOptions} options
|
|
172
|
+
* @returns {import('../types/id.d.ts').IdFilter}
|
|
173
|
+
*/
|
|
174
|
+
export function buildIdFilter(options) {
|
|
175
|
+
const { include = [], exclude = [], extensions = DEFAULT_SVELTE_EXT } = options;
|
|
176
|
+
// this regex combines configured extensions and looks for them at the end of the string or directly before first ? or #
|
|
177
|
+
const extensionsRE = new RegExp(
|
|
178
|
+
`^[^?#]+\\.(?:${extensions
|
|
179
|
+
.map((e) => (e.startsWith('.') ? e.slice(1) : e))
|
|
180
|
+
.map(escapeRE)
|
|
181
|
+
.join('|')})(?:[?#]|$)`
|
|
182
|
+
);
|
|
183
|
+
return {
|
|
184
|
+
id: {
|
|
185
|
+
include: [extensionsRE, .../**@type {Array<string|RegExp>}*/ arraify(include)],
|
|
186
|
+
exclude: /**@type {Array<string|RegExp>}*/ [
|
|
187
|
+
'\0',
|
|
188
|
+
SVELTE_VIRTUAL_STYLE_ID_REGEX, // exclude from regular pipeline, we load it in a separate plugin
|
|
189
|
+
...arraify(exclude)
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* @param {import('../types/options.d.ts').ResolvedOptions} options
|
|
197
|
+
* @returns {import('../types/id.d.ts').IdParser}
|
|
198
|
+
*/
|
|
199
|
+
export function buildIdParser(options) {
|
|
200
|
+
const normalizedRoot = normalizePath(options.root);
|
|
201
|
+
return (id, ssr, timestamp = Date.now()) => {
|
|
202
|
+
const { filename, rawQuery } = splitId(id);
|
|
203
|
+
return parseToSvelteRequest(id, filename, rawQuery, normalizedRoot, timestamp, ssr);
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* @param {import('../types/options.d.ts').ResolvedOptions} options
|
|
209
|
+
* @returns {import('../types/id.d.ts').IdFilter}
|
|
210
|
+
*/
|
|
211
|
+
export function buildModuleIdFilter(options) {
|
|
212
|
+
const {
|
|
213
|
+
infixes = DEFAULT_SVELTE_MODULE_INFIX,
|
|
214
|
+
include = [],
|
|
215
|
+
exclude = [],
|
|
216
|
+
extensions = DEFAULT_SVELTE_MODULE_EXT
|
|
217
|
+
} = options.experimental?.compileModule ?? {};
|
|
218
|
+
// this regex combines configured infixes and extensions
|
|
219
|
+
// and looks for them at the end of the string or directly before first ? or #
|
|
220
|
+
const infixWithExtRE = new RegExp(
|
|
221
|
+
`^[^?#]+(?:${infixes.map(escapeRE).join('|')})(?:[^.\\\\/]+\\.)*(?:${extensions
|
|
222
|
+
.map((e) => (e.startsWith('.') ? e.slice(1) : e))
|
|
223
|
+
.map(escapeRE)
|
|
224
|
+
.join('|')})(?:[?#]|$)`
|
|
225
|
+
);
|
|
226
|
+
return {
|
|
227
|
+
id: {
|
|
228
|
+
include: [infixWithExtRE, .../**@type {Array<string|RegExp>}*/ arraify(include)],
|
|
229
|
+
exclude: ['\0', .../**@type {Array<string|RegExp>}*/ arraify(exclude)]
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* @param {import('../types/options.d.ts').ResolvedOptions} options
|
|
236
|
+
* @returns {import('../types/id.d.ts').ModuleIdParser}
|
|
237
|
+
*/
|
|
238
|
+
export function buildModuleIdParser(options) {
|
|
239
|
+
const root = options.root;
|
|
240
|
+
const normalizedRoot = normalizePath(root);
|
|
241
|
+
return (id, ssr, timestamp = Date.now()) => {
|
|
242
|
+
const { filename, rawQuery } = splitId(id);
|
|
243
|
+
return parseToSvelteModuleRequest(id, filename, rawQuery, normalizedRoot, timestamp, ssr);
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* @param {string} id
|
|
249
|
+
* @param {string} filename
|
|
250
|
+
* @param {string} rawQuery
|
|
251
|
+
* @param {string} root
|
|
252
|
+
* @param {number} timestamp
|
|
253
|
+
* @param {boolean} ssr
|
|
254
|
+
* @returns {import('../types/id.d.ts').SvelteModuleRequest | undefined}
|
|
255
|
+
*/
|
|
256
|
+
function parseToSvelteModuleRequest(id, filename, rawQuery, root, timestamp, ssr) {
|
|
257
|
+
const query = parseRequestQuery(rawQuery);
|
|
258
|
+
|
|
259
|
+
if (query.url || query.raw || query.direct) {
|
|
260
|
+
// skip requests with special vite tags
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const normalizedFilename = normalize(filename, root);
|
|
265
|
+
|
|
266
|
+
return {
|
|
267
|
+
id,
|
|
268
|
+
filename,
|
|
269
|
+
normalizedFilename,
|
|
270
|
+
query,
|
|
271
|
+
timestamp,
|
|
272
|
+
ssr
|
|
273
|
+
};
|
|
274
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import process from 'node:process';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
import { log } from './log.js';
|
|
6
|
+
|
|
7
|
+
export const knownSvelteConfigNames = ['js', 'ts', 'mjs', 'mts'].map(
|
|
8
|
+
(ext) => `svelte.config.${ext}`
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} filePath
|
|
13
|
+
* @param {number} timestamp
|
|
14
|
+
*/
|
|
15
|
+
async function dynamicImportDefault(filePath, timestamp) {
|
|
16
|
+
return await import(filePath + '?t=' + timestamp).then((m) => m.default);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {import('vite').UserConfig} [viteConfig]
|
|
21
|
+
* @param {Partial<import('../public.d.ts').Options>} [inlineOptions]
|
|
22
|
+
* @returns {Promise<Partial<import('../public.d.ts').SvelteConfig> | undefined>}
|
|
23
|
+
*/
|
|
24
|
+
export async function loadSvelteConfig(viteConfig, inlineOptions) {
|
|
25
|
+
if (inlineOptions?.configFile === false) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const configFile = findConfigToLoad(viteConfig, inlineOptions);
|
|
29
|
+
if (configFile) {
|
|
30
|
+
try {
|
|
31
|
+
const result = await dynamicImportDefault(
|
|
32
|
+
pathToFileURL(configFile).href,
|
|
33
|
+
fs.statSync(configFile).mtimeMs
|
|
34
|
+
);
|
|
35
|
+
if (result != null) {
|
|
36
|
+
return {
|
|
37
|
+
...result,
|
|
38
|
+
configFile
|
|
39
|
+
};
|
|
40
|
+
} else {
|
|
41
|
+
throw new Error(`invalid export in ${configFile}`);
|
|
42
|
+
}
|
|
43
|
+
} catch (e) {
|
|
44
|
+
log.error(`failed to import config ${configFile}`, e);
|
|
45
|
+
throw e;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @param {import('vite').UserConfig | undefined} viteConfig
|
|
52
|
+
* @param {Partial<import('../public.d.ts').Options> | undefined} inlineOptions
|
|
53
|
+
* @returns {string | undefined}
|
|
54
|
+
*/
|
|
55
|
+
function findConfigToLoad(viteConfig, inlineOptions) {
|
|
56
|
+
const root = viteConfig?.root || process.cwd();
|
|
57
|
+
if (inlineOptions?.configFile) {
|
|
58
|
+
const abolutePath = path.isAbsolute(inlineOptions.configFile)
|
|
59
|
+
? inlineOptions.configFile
|
|
60
|
+
: path.resolve(root, inlineOptions.configFile);
|
|
61
|
+
if (!fs.existsSync(abolutePath)) {
|
|
62
|
+
throw new Error(`failed to find svelte config file ${abolutePath}.`);
|
|
63
|
+
}
|
|
64
|
+
return abolutePath;
|
|
65
|
+
} else {
|
|
66
|
+
const existingKnownConfigFiles = knownSvelteConfigNames
|
|
67
|
+
.map((candidate) => path.resolve(root, candidate))
|
|
68
|
+
.filter((file) => fs.existsSync(file));
|
|
69
|
+
if (existingKnownConfigFiles.length === 0) {
|
|
70
|
+
log.info(`no Svelte config found at ${root} - using default configuration.`);
|
|
71
|
+
return;
|
|
72
|
+
} else if (existingKnownConfigFiles.length > 1) {
|
|
73
|
+
log.warn(
|
|
74
|
+
`found more than one svelte config file, using ${existingKnownConfigFiles[0]}. you should only have one!`,
|
|
75
|
+
existingKnownConfigFiles
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return existingKnownConfigFiles[0];
|
|
79
|
+
}
|
|
80
|
+
}
|
package/src/utils/log.js
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
|
4
|
+
import { styleText } from 'node:util';
|
|
5
|
+
const cyan = (/** @type {string} */ txt) => styleText('cyan', txt);
|
|
6
|
+
const yellow = (/** @type {string} */ txt) => styleText('yellow', txt);
|
|
7
|
+
const red = (/** @type {string} */ txt) => styleText('red', txt);
|
|
8
|
+
|
|
9
|
+
import { createDebug, enabled } from 'obug';
|
|
10
|
+
|
|
11
|
+
/** @type {import('../types/log.d.ts').LogLevel[]} */
|
|
12
|
+
const levels = ['debug', 'info', 'warn', 'error', 'silent'];
|
|
13
|
+
const prefix = 'vite-plugin-svelte';
|
|
14
|
+
/** @type {Record<import('../types/log.d.ts').LogLevel, any>} */
|
|
15
|
+
const loggers = {
|
|
16
|
+
debug: {
|
|
17
|
+
log: createDebug(`${prefix}`),
|
|
18
|
+
enabled: false,
|
|
19
|
+
isDebug: true
|
|
20
|
+
},
|
|
21
|
+
info: {
|
|
22
|
+
color: cyan,
|
|
23
|
+
log: console.log,
|
|
24
|
+
enabled: true
|
|
25
|
+
},
|
|
26
|
+
warn: {
|
|
27
|
+
color: yellow,
|
|
28
|
+
log: console.warn,
|
|
29
|
+
enabled: true
|
|
30
|
+
},
|
|
31
|
+
error: {
|
|
32
|
+
color: red,
|
|
33
|
+
log: console.error,
|
|
34
|
+
enabled: true
|
|
35
|
+
},
|
|
36
|
+
silent: {
|
|
37
|
+
enabled: false
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/** @type {import('../types/log.d.ts').LogLevel} */
|
|
42
|
+
let _level = 'info';
|
|
43
|
+
/**
|
|
44
|
+
* @param {import('../types/log.d.ts').LogLevel} level
|
|
45
|
+
* @returns {void}
|
|
46
|
+
*/
|
|
47
|
+
function setLevel(level) {
|
|
48
|
+
if (level === _level) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const levelIndex = levels.indexOf(level);
|
|
52
|
+
if (levelIndex > -1) {
|
|
53
|
+
_level = level;
|
|
54
|
+
for (let i = 0; i < levels.length; i++) {
|
|
55
|
+
loggers[levels[i]].enabled = i >= levelIndex;
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
_log(loggers.error, `invalid log level: ${level} `);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @param {any} logger
|
|
64
|
+
* @param {string} message
|
|
65
|
+
* @param {any} [payload]
|
|
66
|
+
* @param {string} [namespace]
|
|
67
|
+
* @returns
|
|
68
|
+
*/
|
|
69
|
+
function _log(logger, message, payload, namespace) {
|
|
70
|
+
if (!logger.enabled) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (logger.isDebug) {
|
|
74
|
+
let log = logger.log;
|
|
75
|
+
if (namespace) {
|
|
76
|
+
if (!isDebugNamespaceEnabled(namespace)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
log = logger.log.extend(namespace);
|
|
80
|
+
}
|
|
81
|
+
if (payload !== undefined) {
|
|
82
|
+
log(message, payload);
|
|
83
|
+
} else {
|
|
84
|
+
log(message);
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
logger.log(
|
|
88
|
+
logger.color(
|
|
89
|
+
`${new Date().toLocaleTimeString()} [${prefix}${
|
|
90
|
+
namespace ? `:${namespace}` : ''
|
|
91
|
+
}] ${message}`
|
|
92
|
+
)
|
|
93
|
+
);
|
|
94
|
+
if (payload) {
|
|
95
|
+
logger.log(payload);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @param {import('../types/log.d.ts').LogLevel} level
|
|
102
|
+
* @returns {import('../types/log.d.ts').LogFn}
|
|
103
|
+
*/
|
|
104
|
+
function createLogger(level) {
|
|
105
|
+
const logger = loggers[level];
|
|
106
|
+
const logFn = /** @type {import('../types/log.d.ts').LogFn} */ (_log.bind(null, logger));
|
|
107
|
+
/** @type {Set<string>} */
|
|
108
|
+
const logged = new Set();
|
|
109
|
+
/** @type {import('../types/log.d.ts').SimpleLogFn} */
|
|
110
|
+
const once = function (message, payload, namespace) {
|
|
111
|
+
if (!logger.enabled || logged.has(message)) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
logged.add(message);
|
|
115
|
+
logFn.apply(null, [message, payload, namespace]);
|
|
116
|
+
};
|
|
117
|
+
Object.defineProperty(logFn, 'enabled', {
|
|
118
|
+
get() {
|
|
119
|
+
return logger.enabled;
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
Object.defineProperty(logFn, 'once', {
|
|
123
|
+
get() {
|
|
124
|
+
return once;
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
return logFn;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export const log = {
|
|
131
|
+
debug: createLogger('debug'),
|
|
132
|
+
info: createLogger('info'),
|
|
133
|
+
warn: createLogger('warn'),
|
|
134
|
+
error: createLogger('error'),
|
|
135
|
+
setLevel
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* @param {import('../types/id.d.ts').SvelteRequest | import('../types/id.d.ts').SvelteModuleRequest} svelteRequest
|
|
140
|
+
* @param {import('@rsvelte/compiler').Warning[]} warnings
|
|
141
|
+
* @param {import('../types/options.d.ts').ResolvedOptions} options
|
|
142
|
+
*/
|
|
143
|
+
export function logCompilerWarnings(svelteRequest, warnings, options) {
|
|
144
|
+
const { emitCss, onwarn, isBuild } = options;
|
|
145
|
+
const sendViaWS = !isBuild && options.experimental?.sendWarningsToBrowser;
|
|
146
|
+
let warn = isBuild ? warnBuild : warnDev;
|
|
147
|
+
/** @type {import('@rsvelte/compiler').Warning[]} */
|
|
148
|
+
const handledByDefaultWarn = [];
|
|
149
|
+
const allWarnings = warnings?.filter((w) => !ignoreCompilerWarning(w, isBuild, emitCss));
|
|
150
|
+
if (sendViaWS) {
|
|
151
|
+
const _warn = warn;
|
|
152
|
+
/** @type {(w: import('@rsvelte/compiler').Warning) => void} */
|
|
153
|
+
warn = (w) => {
|
|
154
|
+
handledByDefaultWarn.push(w);
|
|
155
|
+
_warn(w);
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
allWarnings.forEach((warning) => {
|
|
159
|
+
if (onwarn) {
|
|
160
|
+
onwarn(warning, warn);
|
|
161
|
+
} else {
|
|
162
|
+
warn(warning);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
if (sendViaWS) {
|
|
166
|
+
/** @type {import('../types/log.d.ts').SvelteWarningsMessage} */
|
|
167
|
+
const message = {
|
|
168
|
+
id: svelteRequest.id,
|
|
169
|
+
filename: svelteRequest.filename,
|
|
170
|
+
normalizedFilename: svelteRequest.normalizedFilename,
|
|
171
|
+
timestamp: svelteRequest.timestamp,
|
|
172
|
+
warnings: handledByDefaultWarn, // allWarnings filtered by warnings where onwarn did not call the default handler
|
|
173
|
+
allWarnings, // includes warnings filtered by onwarn and our extra vite plugin svelte warnings
|
|
174
|
+
rawWarnings: warnings // raw compiler output
|
|
175
|
+
};
|
|
176
|
+
log.debug(`sending svelte:warnings message for ${svelteRequest.normalizedFilename}`);
|
|
177
|
+
options.server?.ws?.send('svelte:warnings', message);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @param {import('@rsvelte/compiler').Warning} warning
|
|
183
|
+
* @param {boolean} isBuild
|
|
184
|
+
* @param {boolean} [emitCss]
|
|
185
|
+
* @returns {boolean}
|
|
186
|
+
*/
|
|
187
|
+
function ignoreCompilerWarning(warning, isBuild, emitCss) {
|
|
188
|
+
return (
|
|
189
|
+
(!emitCss && warning.code === 'css_unused_selector') || // same as rollup-plugin-svelte
|
|
190
|
+
(!isBuild && isNoScopableElementWarning(warning))
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
*
|
|
196
|
+
* @param {import('@rsvelte/compiler').Warning} warning
|
|
197
|
+
* @returns {boolean}
|
|
198
|
+
*/
|
|
199
|
+
function isNoScopableElementWarning(warning) {
|
|
200
|
+
// see https://github.com/sveltejs/vite-plugin-svelte/issues/153
|
|
201
|
+
return warning.code === 'css_unused_selector' && warning.message.includes('"*"');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* @param {import('@rsvelte/compiler').Warning} w
|
|
206
|
+
*/
|
|
207
|
+
function warnDev(w) {
|
|
208
|
+
if (w.filename?.includes('node_modules')) {
|
|
209
|
+
if (isDebugNamespaceEnabled('node-modules-onwarn')) {
|
|
210
|
+
log.debug(buildExtendedLogMessage(w), undefined, 'node-modules-onwarn');
|
|
211
|
+
}
|
|
212
|
+
} else if (log.info.enabled) {
|
|
213
|
+
log.info(buildExtendedLogMessage(w));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* @param {import('@rsvelte/compiler').Warning & {frame?: string}} w
|
|
219
|
+
*/
|
|
220
|
+
function warnBuild(w) {
|
|
221
|
+
if (w.filename?.includes('node_modules')) {
|
|
222
|
+
if (isDebugNamespaceEnabled('node-modules-onwarn')) {
|
|
223
|
+
log.debug(buildExtendedLogMessage(w), w.frame, 'node-modules-onwarn');
|
|
224
|
+
}
|
|
225
|
+
} else if (log.warn.enabled) {
|
|
226
|
+
log.warn(buildExtendedLogMessage(w), w.frame);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @param {import('@rsvelte/compiler').Warning} w
|
|
232
|
+
*/
|
|
233
|
+
export function buildExtendedLogMessage(w) {
|
|
234
|
+
const parts = [];
|
|
235
|
+
if (w.filename) {
|
|
236
|
+
parts.push(w.filename);
|
|
237
|
+
}
|
|
238
|
+
if (w.start) {
|
|
239
|
+
parts.push(':', w.start.line, ':', w.start.column);
|
|
240
|
+
}
|
|
241
|
+
if (w.message) {
|
|
242
|
+
if (parts.length > 0) {
|
|
243
|
+
parts.push(' ');
|
|
244
|
+
}
|
|
245
|
+
parts.push(w.message);
|
|
246
|
+
}
|
|
247
|
+
return parts.join('');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* @param {string} namespace
|
|
252
|
+
* @returns {boolean}
|
|
253
|
+
*/
|
|
254
|
+
export function isDebugNamespaceEnabled(namespace) {
|
|
255
|
+
return enabled(`${prefix}:${namespace}`);
|
|
256
|
+
}
|