UNPKG

@sveltejs/kit

Version:

SvelteKit is the fastest way to build Svelte apps

137 lines (112 loc) • 3.91 kB
/** @import { Plugin, ResolvedConfig } from 'vite' */ /** @import { EnvVarConfig } from '@sveltejs/kit/env' */ /** @import { ValidatedConfig } from 'types' */ import path from 'node:path'; import { exactRegex } from '@rolldown/pluginutils'; import * as sync from '../../../core/sync/sync.js'; import { create_env_modules, resolve_env_entry } from '../../../core/env.js'; import { import_peer } from '../../../utils/import.js'; import { write_if_changed } from '../../../core/sync/utils.js'; import { posixify } from '../../../utils/os.js'; /** * Generate (and, in dev, maintain) the `${outDir}/generated/{build,dev}/env` modules * derived from `src/env.ts` * * @param {ValidatedConfig} config * @param {(variables: Record<string, EnvVarConfig<any>> | null) => void} callback * @returns {Plugin} */ export function plugin_env_vars(config, callback) { /** @type {string} */ let dir; /** @type {Record<string, any>} */ let env; /** @type {ResolvedConfig} */ let resolved_config; /** @type {Set<string>} */ let deps = new Set(); let is_build = false; /** @type {Promise<void> | undefined} */ let generated; async function generate() { const entry = resolve_env_entry(config, resolved_config.root); const synced = await sync.env(config, entry, resolved_config.root, resolved_config.mode); deps = synced.deps; const vars = synced.variables; callback(vars); const modules = create_env_modules( config, vars, env, dir, entry && posixify(path.relative(dir, entry)), !is_build ); for (const [file, code] of Object.entries(modules)) { write_if_changed(`${dir}/${file}`, code); } } return { name: 'vite-plugin-sveltekit-env-vars', async configResolved(c) { resolved_config = c; const vite = await import_peer('vite', c.root); env = vite.loadEnv(c.mode, path.resolve(c.root, config.env.dir), ''); is_build = c.command === 'build'; dir = posixify( path.resolve(c.root, config.outDir, `generated/${is_build ? 'build' : 'dev'}/env`) ); }, async buildStart() { // runs once via the memo — per-process, whichever environment starts first // (environment names vary by adapter), and never in the postbuild forks, // which resolve the config without building await (generated ??= generate()); }, async hotUpdate({ type, file }) { // runs for every environment; the generated modules are shared, so do the work once if (this.environment.name !== 'client') return; const created = type === 'create' && file === resolve_env_entry(config, resolved_config.root); if (!deps.has(file) && !created) return; await generate(); if (type !== 'update') this.environment.hot.send({ type: 'full-reload' }); } }; } /** * @param {() => string | null} get_service_worker_entry_file * @returns {Plugin} */ export function plugin_service_worker_env_vars(get_service_worker_entry_file) { /** @type {string | null} */ let service_worker_entry_file; /** @satisfies {Plugin} */ const plugin = { name: 'vite-plugin-sveltekit-service-worker-env', configResolved() { service_worker_entry_file = get_service_worker_entry_file(); if (service_worker_entry_file) { plugin.transform.filter = { id: exactRegex(service_worker_entry_file) }; } }, applyToEnvironment(environment) { return !!service_worker_entry_file && environment.config.consumer === 'client'; }, transform: { filter: {}, handler(code) { // prepend the service worker with an import that configures // `env`, in case `$app/env/public` is imported. In production // this is required: dynamic public env vars aren't known at // build time, so `env.js` is loaded at runtime. In dev, the // imported module just inlines the current values instead. return { code: `import '<sveltekit:generated>/env/service-worker.js';\n${code}` }; } } }; return plugin; }