@sveltejs/vite-plugin-svelte
Advanced tools
Comparing version 1.2.0 to 1.3.0
@@ -81,5 +81,7 @@ import { UserConfig, Plugin } from 'vite'; | ||
/** | ||
* Force Vite to pre-bundle Svelte libraries | ||
* Enable support for Vite's dependency optimization to prebundle Svelte libraries. | ||
* | ||
* @default false | ||
* To disable prebundling for a specific library, add it to `optimizeDeps.exclude`. | ||
* | ||
* @default true for dev, false for build | ||
*/ | ||
@@ -175,2 +177,8 @@ prebundleSvelteLibraries?: boolean; | ||
sendWarningsToBrowser?: boolean; | ||
/** | ||
* disable svelte compile statistics | ||
* | ||
* @default false | ||
*/ | ||
disableCompileStats?: 'dev' | 'build' | boolean; | ||
} | ||
@@ -177,0 +185,0 @@ interface InspectorOptions { |
{ | ||
"name": "@sveltejs/vite-plugin-svelte", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"license": "MIT", | ||
@@ -68,3 +68,3 @@ "author": "dominikg", | ||
"rollup": "^2.79.1", | ||
"svelte": "3.53.1", | ||
"svelte": "^3.53.1", | ||
"tsup": "^6.5.0", | ||
@@ -71,0 +71,0 @@ "vite": "^3.2.3" |
@@ -18,3 +18,2 @@ import fs from 'fs'; | ||
} from './utils/options'; | ||
import { VitePluginSvelteCache } from './utils/vite-plugin-svelte-cache'; | ||
@@ -27,2 +26,3 @@ import { ensureWatchedFile, setupWatchers } from './utils/watch'; | ||
import { svelteInspector } from './ui/inspector/plugin'; | ||
import { VitePluginSvelteCache } from './utils/vite-plugin-svelte-cache'; | ||
@@ -233,2 +233,5 @@ interface PluginAPI { | ||
} | ||
}, | ||
async buildEnd() { | ||
await options.stats?.finishAll(); | ||
} | ||
@@ -235,0 +238,0 @@ } |
@@ -8,7 +8,9 @@ import { CompileOptions, ResolvedOptions } from './options'; | ||
import { log } from './log'; | ||
import { StatCollection } from './vite-plugin-svelte-stats'; | ||
const scriptLangRE = /<script [^>]*lang=["']?([^"' >]+)["']?[^>]*>/; | ||
const _createCompileSvelte = (makeHot: Function) => | ||
async function compileSvelte( | ||
const _createCompileSvelte = (makeHot: Function) => { | ||
let stats: StatCollection | undefined; | ||
return async function compileSvelte( | ||
svelteRequest: SvelteRequest, | ||
@@ -22,2 +24,27 @@ code: string, | ||
if (options.stats) { | ||
if (options.isBuild) { | ||
if (!stats) { | ||
// build is either completely ssr or csr, create stats collector on first compile | ||
// it is then finished in the buildEnd hook. | ||
stats = options.stats.startCollection(`${ssr ? 'ssr' : 'dom'} compile`, { | ||
logInProgress: () => false | ||
}); | ||
} | ||
} else { | ||
// dev time ssr, it's a ssr request and there are no stats, assume new page load and start collecting | ||
if (ssr && !stats) { | ||
stats = options.stats.startCollection('ssr compile'); | ||
} | ||
// stats are being collected but this isn't an ssr request, assume page loaded and stop collecting | ||
if (!ssr && stats) { | ||
stats.finish(); | ||
stats = undefined; | ||
} | ||
// TODO find a way to trace dom compile during dev | ||
// problem: we need to call finish at some point but have no way to tell if page load finished | ||
// also they for hmr updates too | ||
} | ||
} | ||
const compileOptions: CompileOptions = { | ||
@@ -72,3 +99,9 @@ ...options.compilerOptions, | ||
: compileOptions; | ||
const endStat = stats?.start(filename); | ||
const compiled = compile(finalCode, finalCompileOptions); | ||
if (endStat) { | ||
endStat(); | ||
} | ||
const hasCss = compiled.css?.code?.trim().length > 0; | ||
@@ -105,3 +138,3 @@ // compiler might not emit css with mode none or it may be empty | ||
}; | ||
}; | ||
function buildMakeHot(options: ResolvedOptions) { | ||
@@ -108,0 +141,0 @@ const needsMakeHot = options.hot !== false && options.isServe && !options.isProduction; |
@@ -21,1 +21,3 @@ const VITE_RESOLVE_MAIN_FIELDS = ['module', 'jsnext:main', 'jsnext']; | ||
]; | ||
export const SVELTE_EXPORT_CONDITIONS = ['svelte']; |
@@ -1,2 +0,2 @@ | ||
import { promises as fs } from 'fs'; | ||
import { readFileSync } from 'fs'; | ||
import { compile, preprocess } from 'svelte/compiler'; | ||
@@ -9,2 +9,3 @@ import { DepOptimizationOptions } from 'vite'; | ||
import { atLeastSvelte } from './svelte-version'; | ||
import { StatCollection } from './vite-plugin-svelte-stats'; | ||
@@ -27,7 +28,12 @@ type EsbuildOptions = NonNullable<DepOptimizationOptions['esbuildOptions']>; | ||
const svelteFilter = new RegExp(`\\.(` + svelteExtensions.join('|') + `)(\\?.*)?$`); | ||
let statsCollection: StatCollection | undefined; | ||
build.onStart(() => { | ||
statsCollection = options.stats?.startCollection('prebundle libraries', { | ||
logResult: (c) => c.stats.length > 1 | ||
}); | ||
}); | ||
build.onLoad({ filter: svelteFilter }, async ({ path: filename }) => { | ||
const code = await fs.readFile(filename, 'utf8'); | ||
const code = readFileSync(filename, 'utf8'); | ||
try { | ||
const contents = await compileSvelte(options, { filename, code }); | ||
const contents = await compileSvelte(options, { filename, code }, statsCollection); | ||
return { contents }; | ||
@@ -38,2 +44,5 @@ } catch (e) { | ||
}); | ||
build.onEnd(() => { | ||
statsCollection?.finish(); | ||
}); | ||
} | ||
@@ -45,3 +54,4 @@ }; | ||
options: ResolvedOptions, | ||
{ filename, code }: { filename: string; code: string } | ||
{ filename, code }: { filename: string; code: string }, | ||
statsCollection?: StatCollection | ||
): Promise<string> { | ||
@@ -90,6 +100,8 @@ let css = options.compilerOptions.css; | ||
: compileOptions; | ||
const endStat = statsCollection?.start(filename); | ||
const compiled = compile(finalCode, finalCompileOptions) as Compiled; | ||
if (endStat) { | ||
endStat(); | ||
} | ||
return compiled.js.code + '//# sourceMappingURL=' + compiled.js.map.toUrl(); | ||
} |
@@ -5,3 +5,8 @@ /* eslint-disable no-unused-vars */ | ||
import { loadSvelteConfig } from './load-svelte-config'; | ||
import { SVELTE_HMR_IMPORTS, SVELTE_IMPORTS, SVELTE_RESOLVE_MAIN_FIELDS } from './constants'; | ||
import { | ||
SVELTE_EXPORT_CONDITIONS, | ||
SVELTE_HMR_IMPORTS, | ||
SVELTE_IMPORTS, | ||
SVELTE_RESOLVE_MAIN_FIELDS | ||
} from './constants'; | ||
// eslint-disable-next-line node/no-missing-import | ||
@@ -31,2 +36,3 @@ import type { CompileOptions, Warning } from 'svelte/types/compiler/interfaces'; | ||
import { isCommonDepWithoutSvelteField } from './dependencies'; | ||
import { VitePluginSvelteStats } from './vite-plugin-svelte-stats'; | ||
@@ -134,5 +140,7 @@ // svelte 3.53.0 changed compilerOptions.css from boolean to string | boolen, use string when available | ||
}; | ||
const isBuild = viteEnv.command === 'build'; | ||
const defaultOptions: Partial<Options> = { | ||
extensions: ['.svelte'], | ||
emitCss: true | ||
emitCss: true, | ||
prebundleSvelteLibraries: !isBuild | ||
}; | ||
@@ -145,3 +153,3 @@ const svelteConfig = convertPluginOptions( | ||
root: viteConfigWithResolvedRoot.root!, | ||
isBuild: viteEnv.command === 'build', | ||
isBuild, | ||
isServe: viteEnv.command === 'serve', | ||
@@ -210,2 +218,10 @@ isDebug: process.env.DEBUG != null | ||
enforceOptionsForProduction(merged); | ||
// mergeConfigs would mangle functions on the stats class, so do this afterwards | ||
const isLogLevelInfo = [undefined, 'info'].includes(viteConfig.logLevel); | ||
const disableCompileStats = merged.experimental?.disableCompileStats; | ||
const statsEnabled = | ||
disableCompileStats !== true && disableCompileStats !== (merged.isBuild ? 'build' : 'dev'); | ||
if (statsEnabled && isLogLevelInfo) { | ||
merged.stats = new VitePluginSvelteStats(); | ||
} | ||
return merged; | ||
@@ -323,3 +339,4 @@ } | ||
mainFields: [...SVELTE_RESOLVE_MAIN_FIELDS], | ||
dedupe: [...SVELTE_IMPORTS, ...SVELTE_HMR_IMPORTS] | ||
dedupe: [...SVELTE_IMPORTS, ...SVELTE_HMR_IMPORTS], | ||
conditions: [...SVELTE_EXPORT_CONDITIONS] | ||
} | ||
@@ -367,8 +384,13 @@ // this option is still awaiting a PR in vite to be supported | ||
if (options.prebundleSvelteLibraries) { | ||
extraViteConfig.optimizeDeps.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()` | ||
extraViteConfig.optimizeDeps.esbuildOptions = { | ||
plugins: [{ name: facadeEsbuildSveltePluginName, setup: () => {} }] | ||
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: () => {} }] | ||
} | ||
}; | ||
@@ -387,5 +409,40 @@ } | ||
} | ||
validateViteConfig(extraViteConfig, config, options); | ||
return extraViteConfig; | ||
} | ||
function validateViteConfig( | ||
extraViteConfig: Partial<UserConfig>, | ||
config: UserConfig, | ||
options: PreResolvedOptions | ||
) { | ||
const { prebundleSvelteLibraries, isBuild } = options; | ||
if (prebundleSvelteLibraries) { | ||
const isEnabled = (option: 'dev' | 'build' | boolean) => | ||
option !== true && option !== (isBuild ? 'build' : 'dev'); | ||
const logWarning = (name: string, value: 'dev' | 'build' | boolean, recommendation: string) => | ||
log.warn.once( | ||
`Incompatible options: \`prebundleSvelteLibraries: true\` and vite \`${name}: ${JSON.stringify( | ||
value | ||
)}\` ${isBuild ? 'during build.' : '.'} ${recommendation}` | ||
); | ||
const viteOptimizeDepsDisabled = config.optimizeDeps?.disabled ?? 'build'; // fall back to vite default | ||
const isOptimizeDepsEnabled = isEnabled(viteOptimizeDepsDisabled); | ||
if (!isBuild && !isOptimizeDepsEnabled) { | ||
logWarning( | ||
'optimizeDeps.disabled', | ||
viteOptimizeDepsDisabled, | ||
'Forcing `optimizeDeps.disabled: "build"`. Disable prebundleSvelteLibraries or update your vite config to enable optimizeDeps during dev.' | ||
); | ||
extraViteConfig.optimizeDeps!.disabled = 'build'; | ||
} else if (isBuild && isOptimizeDepsEnabled) { | ||
logWarning( | ||
'optimizeDeps.disabled', | ||
viteOptimizeDepsDisabled, | ||
'Disable optimizeDeps or prebundleSvelteLibraries for build if you experience errors.' | ||
); | ||
} | ||
} | ||
} | ||
async function buildExtraConfigForDependencies(options: PreResolvedOptions, config: UserConfig) { | ||
@@ -398,3 +455,13 @@ // extra handling for svelte dependencies in the project | ||
isFrameworkPkgByJson(pkgJson) { | ||
return !!pkgJson.svelte; | ||
let hasSvelteCondition = false; | ||
if (typeof pkgJson.exports === 'object') { | ||
// use replacer as a simple way to iterate over nested keys | ||
JSON.stringify(pkgJson.exports, (key, value) => { | ||
if (SVELTE_EXPORT_CONDITIONS.includes(key)) { | ||
hasSvelteCondition = true; | ||
} | ||
return value; | ||
}); | ||
} | ||
return hasSvelteCondition || !!pkgJson.svelte; | ||
}, | ||
@@ -563,5 +630,7 @@ isSemiFrameworkPkgByJson(pkgJson) { | ||
/** | ||
* Force Vite to pre-bundle Svelte libraries | ||
* Enable support for Vite's dependency optimization to prebundle Svelte libraries. | ||
* | ||
* @default false | ||
* To disable prebundling for a specific library, add it to `optimizeDeps.exclude`. | ||
* | ||
* @default true for dev, false for build | ||
*/ | ||
@@ -668,2 +737,9 @@ prebundleSvelteLibraries?: boolean; | ||
sendWarningsToBrowser?: boolean; | ||
/** | ||
* disable svelte compile statistics | ||
* | ||
* @default false | ||
*/ | ||
disableCompileStats?: 'dev' | 'build' | boolean; | ||
} | ||
@@ -755,2 +831,3 @@ | ||
server?: ViteDevServer; | ||
stats?: VitePluginSvelteStats; | ||
} | ||
@@ -757,0 +834,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
581820
34
7721
34