|
import fs from 'node:fs'; |
|
import path from 'node:path'; |
|
|
|
import colors from 'kleur'; |
|
|
|
import { copy, mkdirp, posixify, read, resolve_entry, rimraf } from '../../utils/filesystem.js'; |
|
import { create_static_module, create_dynamic_module } from '../../core/env.js'; |
|
import * as sync from '../../core/sync/sync.js'; |
|
import { create_assets } from '../../core/sync/create_manifest_data/index.js'; |
|
import { runtime_directory, logger } from '../../core/utils.js'; |
|
import { load_config } from '../../core/config/index.js'; |
|
import { generate_manifest } from '../../core/generate_manifest/index.js'; |
|
import { build_server_nodes } from './build/build_server.js'; |
|
import { build_service_worker } from './build/build_service_worker.js'; |
|
import { assets_base, find_deps } from './build/utils.js'; |
|
import { dev } from './dev/index.js'; |
|
import { is_illegal, module_guard, normalize_id } from './graph_analysis/index.js'; |
|
import { preview } from './preview/index.js'; |
|
import { get_config_aliases, get_env, strip_virtual_prefix } from './utils.js'; |
|
import { write_client_manifest } from '../../core/sync/write_client_manifest.js'; |
|
import prerender from '../../core/postbuild/prerender.js'; |
|
import analyse from '../../core/postbuild/analyse.js'; |
|
import { s } from '../../utils/misc.js'; |
|
import { hash } from '../../runtime/hash.js'; |
|
import { dedent, isSvelte5Plus } from '../../core/sync/utils.js'; |
|
import { |
|
env_dynamic_private, |
|
env_dynamic_public, |
|
env_static_private, |
|
env_static_public, |
|
service_worker, |
|
sveltekit_environment, |
|
sveltekit_paths, |
|
sveltekit_server |
|
} from './module_ids.js'; |
|
import { resolve_peer_dependency } from '../../utils/import.js'; |
|
|
|
const cwd = process.cwd(); |
|
|
|
|
|
const enforced_config = { |
|
appType: true, |
|
base: true, |
|
build: { |
|
cssCodeSplit: true, |
|
emptyOutDir: true, |
|
lib: { |
|
entry: true, |
|
name: true, |
|
formats: true |
|
}, |
|
manifest: true, |
|
outDir: true, |
|
rollupOptions: { |
|
input: true, |
|
output: { |
|
format: true, |
|
entryFileNames: true, |
|
chunkFileNames: true, |
|
assetFileNames: true |
|
}, |
|
preserveEntrySignatures: true |
|
}, |
|
ssr: true |
|
}, |
|
publicDir: true, |
|
resolve: { |
|
alias: { |
|
$app: true, |
|
$lib: true, |
|
'$service-worker': true |
|
} |
|
}, |
|
root: true |
|
}; |
|
|
|
const options_regex = /(export\s+const\s+(prerender|csr|ssr|trailingSlash))\s*=/s; |
|
|
|
|
|
const warned = new Set(); |
|
|
|
|
|
const warning_preprocessor = { |
|
script: ({ content, filename }) => { |
|
if (!filename) return; |
|
|
|
const basename = path.basename(filename); |
|
if (basename.startsWith('+page.') || basename.startsWith('+layout.')) { |
|
const match = content.match(options_regex); |
|
if (match) { |
|
const fixed = basename.replace('.svelte', '(.server).js/ts'); |
|
|
|
const message = |
|
`\n${colors.bold().red(path.relative('.', filename))}\n` + |
|
`\`${match[1]}\` will be ignored — move it to ${fixed} instead. See https://kit.svelte.dev/docs/page-options for more information.`; |
|
|
|
if (!warned.has(message)) { |
|
console.log(message); |
|
warned.add(message); |
|
} |
|
} |
|
} |
|
}, |
|
markup: ({ content, filename }) => { |
|
if (!filename) return; |
|
|
|
const basename = path.basename(filename); |
|
const has_children = |
|
content.includes('<slot') || (isSvelte5Plus() && content.includes('{@render')); |
|
|
|
if (basename.startsWith('+layout.') && !has_children) { |
|
const message = |
|
`\n${colors.bold().red(path.relative('.', filename))}\n` + |
|
`\`<slot />\`${isSvelte5Plus() ? ' or `{@render ...}` tag' : ''}` + |
|
' missing — inner content will not be rendered'; |
|
|
|
if (!warned.has(message)) { |
|
console.log(message); |
|
warned.add(message); |
|
} |
|
} |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
export async function sveltekit() { |
|
const svelte_config = await load_config(); |
|
|
|
|
|
let preprocess = svelte_config.preprocess; |
|
if (Array.isArray(preprocess)) { |
|
preprocess = [...preprocess, warning_preprocessor]; |
|
} else if (preprocess) { |
|
preprocess = [preprocess, warning_preprocessor]; |
|
} else { |
|
preprocess = warning_preprocessor; |
|
} |
|
|
|
|
|
const vite_plugin_svelte_options = { |
|
configFile: false, |
|
extensions: svelte_config.extensions, |
|
preprocess, |
|
onwarn: svelte_config.onwarn, |
|
compilerOptions: { |
|
hydratable: isSvelte5Plus() ? undefined : true, |
|
...svelte_config.compilerOptions |
|
}, |
|
...svelte_config.vitePlugin |
|
}; |
|
|
|
const { svelte } = await resolve_peer_dependency('@sveltejs/vite-plugin-svelte'); |
|
|
|
return [...svelte(vite_plugin_svelte_options), ...(await kit({ svelte_config }))]; |
|
} |
|
|
|
|
|
|
|
let secondary_build_started = false; |
|
|
|
|
|
let manifest_data; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function kit({ svelte_config }) { |
|
const vite = await resolve_peer_dependency('vite'); |
|
|
|
const { kit } = svelte_config; |
|
const out = `${kit.outDir}/output`; |
|
|
|
const version_hash = hash(kit.version.name); |
|
|
|
|
|
let vite_config; |
|
|
|
|
|
let vite_config_env; |
|
|
|
|
|
let is_build; |
|
|
|
|
|
let env; |
|
|
|
|
|
let finalise; |
|
|
|
|
|
let initial_config; |
|
|
|
const service_worker_entry_file = resolve_entry(kit.files.serviceWorker); |
|
const parsed_service_worker = path.parse(kit.files.serviceWorker); |
|
|
|
|
|
|
|
|
|
|
|
|
|
const tracked_features = {}; |
|
|
|
const sourcemapIgnoreList = (relative_path) => |
|
relative_path.includes('node_modules') || relative_path.includes(kit.outDir); |
|
|
|
|
|
const plugin_setup = { |
|
name: 'vite-plugin-sveltekit-setup', |
|
|
|
|
|
|
|
|
|
|
|
config(config, config_env) { |
|
initial_config = config; |
|
vite_config_env = config_env; |
|
is_build = config_env.command === 'build'; |
|
|
|
env = get_env(kit.env, vite_config_env.mode); |
|
|
|
const allow = new Set([ |
|
kit.files.lib, |
|
kit.files.routes, |
|
kit.outDir, |
|
path.resolve('src'), |
|
path.resolve('node_modules'), |
|
path.resolve(vite.searchForWorkspaceRoot(cwd), 'node_modules') |
|
]); |
|
|
|
|
|
|
|
const client_hooks = resolve_entry(kit.files.hooks.client); |
|
if (client_hooks) allow.add(path.dirname(client_hooks)); |
|
|
|
const generated = path.posix.join(kit.outDir, 'generated'); |
|
|
|
|
|
|
|
const new_config = { |
|
resolve: { |
|
alias: [ |
|
{ find: '__SERVER__', replacement: `${generated}/server` }, |
|
{ find: '$app', replacement: `${runtime_directory}/app` }, |
|
...get_config_aliases(kit) |
|
] |
|
}, |
|
root: cwd, |
|
server: { |
|
cors: { preflightContinue: true }, |
|
fs: { |
|
allow: [...allow] |
|
}, |
|
sourcemapIgnoreList, |
|
watch: { |
|
ignored: [ |
|
|
|
`${posixify(kit.outDir)}/!(generated)` |
|
] |
|
} |
|
}, |
|
preview: { |
|
cors: { preflightContinue: true } |
|
}, |
|
optimizeDeps: { |
|
entries: [ |
|
`${kit.files.routes}/**/+*.{svelte,js,ts}`, |
|
`!${kit.files.routes}/**/+*server.*` |
|
], |
|
exclude: [ |
|
'@sveltejs/kit', |
|
|
|
|
|
'$app', |
|
'$env' |
|
] |
|
}, |
|
ssr: { |
|
noExternal: [ |
|
|
|
|
|
|
|
|
|
|
|
'esm-env', |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
'@sveltejs/kit' |
|
] |
|
} |
|
}; |
|
|
|
if (is_build) { |
|
if (!new_config.build) new_config.build = {}; |
|
new_config.build.ssr = !secondary_build_started; |
|
|
|
new_config.define = { |
|
__SVELTEKIT_ADAPTER_NAME__: s(kit.adapter?.name), |
|
__SVELTEKIT_APP_VERSION_FILE__: s(`${kit.appDir}/version.json`), |
|
__SVELTEKIT_APP_VERSION_POLL_INTERVAL__: s(kit.version.pollInterval), |
|
__SVELTEKIT_DEV__: 'false', |
|
__SVELTEKIT_EMBEDDED__: kit.embedded ? 'true' : 'false' |
|
}; |
|
|
|
if (!secondary_build_started) { |
|
manifest_data = sync.all(svelte_config, config_env.mode).manifest_data; |
|
} |
|
} else { |
|
new_config.define = { |
|
__SVELTEKIT_APP_VERSION_POLL_INTERVAL__: '0', |
|
__SVELTEKIT_DEV__: 'true', |
|
__SVELTEKIT_EMBEDDED__: kit.embedded ? 'true' : 'false' |
|
}; |
|
|
|
|
|
|
|
(new_config.ssr).external = [ |
|
'cookie', |
|
'set-cookie-parser' |
|
]; |
|
} |
|
|
|
warn_overridden_config(config, new_config); |
|
|
|
return new_config; |
|
}, |
|
|
|
|
|
|
|
|
|
configResolved(config) { |
|
vite_config = config; |
|
} |
|
}; |
|
|
|
|
|
const plugin_virtual_modules = { |
|
name: 'vite-plugin-sveltekit-virtual-modules', |
|
|
|
resolveId(id, importer) { |
|
|
|
|
|
|
|
if (importer) { |
|
const parsed_importer = path.parse(importer); |
|
|
|
const importer_is_service_worker = |
|
parsed_importer.dir === parsed_service_worker.dir && |
|
parsed_importer.name === parsed_service_worker.name; |
|
|
|
if (importer_is_service_worker && id !== '$service-worker' && id !== '$env/static/public') { |
|
throw new Error( |
|
`Cannot import ${id} into service-worker code. Only the modules $service-worker and $env/static/public are available in service workers.` |
|
); |
|
} |
|
} |
|
|
|
|
|
if (id.startsWith('$env/') || id.startsWith('__sveltekit/') || id === '$service-worker') { |
|
return `\0virtual:${id}`; |
|
} |
|
}, |
|
|
|
load(id, options) { |
|
const browser = !options?.ssr; |
|
|
|
const global = is_build |
|
? `globalThis.__sveltekit_${version_hash}` |
|
: 'globalThis.__sveltekit_dev'; |
|
|
|
if (options?.ssr === false && process.env.TEST !== 'true') { |
|
const normalized_cwd = vite.normalizePath(cwd); |
|
const normalized_lib = vite.normalizePath(kit.files.lib); |
|
if ( |
|
is_illegal(id, { |
|
cwd: normalized_cwd, |
|
node_modules: vite.normalizePath(path.resolve('node_modules')), |
|
server: vite.normalizePath(path.join(normalized_lib, 'server')) |
|
}) |
|
) { |
|
const relative = normalize_id(id, normalized_lib, normalized_cwd); |
|
throw new Error(`Cannot import ${strip_virtual_prefix(relative)} into client-side code`); |
|
} |
|
} |
|
|
|
switch (id) { |
|
case env_static_private: |
|
return create_static_module('$env/static/private', env.private); |
|
|
|
case env_static_public: |
|
return create_static_module('$env/static/public', env.public); |
|
|
|
case env_dynamic_private: |
|
return create_dynamic_module( |
|
'private', |
|
vite_config_env.command === 'serve' ? env.private : undefined |
|
); |
|
|
|
case env_dynamic_public: |
|
|
|
if (browser) { |
|
return `export const env = ${global}.env;`; |
|
} |
|
|
|
return create_dynamic_module( |
|
'public', |
|
vite_config_env.command === 'serve' ? env.public : undefined |
|
); |
|
|
|
case service_worker: |
|
return create_service_worker_module(svelte_config); |
|
|
|
|
|
|
|
case sveltekit_paths: { |
|
const { assets, base } = svelte_config.kit.paths; |
|
|
|
|
|
|
|
|
|
if (browser) { |
|
return dedent` |
|
export const base = ${global}?.base ?? ${s(base)}; |
|
export const assets = ${global}?.assets ?? ${assets ? s(assets) : 'base'}; |
|
`; |
|
} |
|
|
|
return dedent` |
|
export let base = ${s(base)}; |
|
export let assets = ${assets ? s(assets) : 'base'}; |
|
|
|
export const relative = ${svelte_config.kit.paths.relative}; |
|
|
|
const initial = { base, assets }; |
|
|
|
export function override(paths) { |
|
base = paths.base; |
|
assets = paths.assets; |
|
} |
|
|
|
export function reset() { |
|
base = initial.base; |
|
assets = initial.assets; |
|
} |
|
|
|
/** @param {string} path */ |
|
export function set_assets(path) { |
|
assets = initial.assets = path; |
|
} |
|
`; |
|
} |
|
|
|
case sveltekit_environment: { |
|
const { version } = svelte_config.kit; |
|
|
|
return dedent` |
|
export const version = ${s(version.name)}; |
|
export let building = false; |
|
export let prerendering = false; |
|
|
|
export function set_building() { |
|
building = true; |
|
} |
|
|
|
export function set_prerendering() { |
|
prerendering = true; |
|
} |
|
`; |
|
} |
|
|
|
case sveltekit_server: { |
|
return dedent` |
|
export let read_implementation = null; |
|
|
|
export let manifest = null; |
|
|
|
export function set_read_implementation(fn) { |
|
read_implementation = fn; |
|
} |
|
|
|
export function set_manifest(_) { |
|
manifest = _; |
|
} |
|
`; |
|
} |
|
} |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
const plugin_guard = { |
|
name: 'vite-plugin-sveltekit-guard', |
|
|
|
writeBundle: { |
|
sequential: true, |
|
handler(_options) { |
|
if (vite_config.build.ssr) return; |
|
|
|
const guard = module_guard(this, { |
|
cwd: vite.normalizePath(process.cwd()), |
|
lib: vite.normalizePath(kit.files.lib) |
|
}); |
|
|
|
manifest_data.nodes.forEach((_node, i) => { |
|
const id = vite.normalizePath( |
|
path.resolve(kit.outDir, `generated/client-optimized/nodes/${i}.js`) |
|
); |
|
|
|
guard.check(id); |
|
}); |
|
} |
|
} |
|
}; |
|
|
|
|
|
const plugin_compile = { |
|
name: 'vite-plugin-sveltekit-compile', |
|
|
|
|
|
|
|
|
|
|
|
config(config) { |
|
|
|
let new_config; |
|
|
|
if (is_build) { |
|
const ssr = (config.build?.ssr); |
|
const prefix = `${kit.appDir}/immutable`; |
|
|
|
|
|
const input = {}; |
|
|
|
if (ssr) { |
|
input.index = `${runtime_directory}/server/index.js`; |
|
input.internal = `${kit.outDir}/generated/server/internal.js`; |
|
|
|
|
|
manifest_data.routes.forEach((route) => { |
|
if (route.endpoint) { |
|
const resolved = path.resolve(route.endpoint.file); |
|
const relative = decodeURIComponent(path.relative(kit.files.routes, resolved)); |
|
const name = posixify(path.join('entries/endpoints', relative.replace(/\.js$/, ''))); |
|
input[name] = resolved; |
|
} |
|
}); |
|
|
|
|
|
manifest_data.nodes.forEach((node) => { |
|
for (const file of [node.component, node.universal, node.server]) { |
|
if (file) { |
|
const resolved = path.resolve(file); |
|
const relative = decodeURIComponent(path.relative(kit.files.routes, resolved)); |
|
|
|
const name = relative.startsWith('..') |
|
? posixify(path.join('entries/fallbacks', path.basename(file))) |
|
: posixify(path.join('entries/pages', relative.replace(/\.js$/, ''))); |
|
input[name] = resolved; |
|
} |
|
} |
|
}); |
|
|
|
|
|
Object.entries(manifest_data.matchers).forEach(([key, file]) => { |
|
const name = posixify(path.join('entries/matchers', key)); |
|
input[name] = path.resolve(file); |
|
}); |
|
} else { |
|
input['entry/start'] = `${runtime_directory}/client/entry.js`; |
|
input['entry/app'] = `${kit.outDir}/generated/client-optimized/app.js`; |
|
|
|
manifest_data.nodes.forEach((node, i) => { |
|
if (node.component || node.universal) { |
|
input[`nodes/${i}`] = `${kit.outDir}/generated/client-optimized/nodes/${i}.js`; |
|
} |
|
}); |
|
} |
|
|
|
|
|
const ext = kit.output.preloadStrategy === 'preload-mjs' ? 'mjs' : 'js'; |
|
|
|
|
|
|
|
|
|
|
|
const client_base = |
|
kit.paths.relative !== false || kit.paths.assets ? './' : kit.paths.base || '/'; |
|
|
|
new_config = { |
|
base: ssr ? assets_base(kit) : client_base, |
|
build: { |
|
copyPublicDir: !ssr, |
|
cssCodeSplit: true, |
|
cssMinify: initial_config.build?.minify == null ? true : !!initial_config.build.minify, |
|
|
|
manifest: '.vite/manifest.json', |
|
outDir: `${out}/${ssr ? 'server' : 'client'}`, |
|
rollupOptions: { |
|
input, |
|
output: { |
|
format: 'esm', |
|
entryFileNames: ssr ? '[name].js' : `${prefix}/[name].[hash].${ext}`, |
|
chunkFileNames: ssr ? 'chunks/[name].js' : `${prefix}/chunks/[name].[hash].${ext}`, |
|
assetFileNames: `${prefix}/assets/[name].[hash][extname]`, |
|
hoistTransitiveImports: false, |
|
sourcemapIgnoreList |
|
}, |
|
preserveEntrySignatures: 'strict' |
|
}, |
|
ssrEmitAssets: true, |
|
target: ssr ? 'node18.13' : undefined |
|
}, |
|
publicDir: kit.files.assets, |
|
worker: { |
|
rollupOptions: { |
|
output: { |
|
entryFileNames: `${prefix}/workers/[name]-[hash].js`, |
|
chunkFileNames: `${prefix}/workers/chunks/[name]-[hash].js`, |
|
assetFileNames: `${prefix}/workers/assets/[name]-[hash][extname]`, |
|
hoistTransitiveImports: false |
|
} |
|
} |
|
} |
|
}; |
|
} else { |
|
new_config = { |
|
appType: 'custom', |
|
base: kit.paths.base, |
|
build: { |
|
rollupOptions: { |
|
|
|
|
|
input: `${runtime_directory}/client/entry.js` |
|
} |
|
}, |
|
publicDir: kit.files.assets |
|
}; |
|
} |
|
|
|
warn_overridden_config(config, new_config); |
|
|
|
return new_config; |
|
}, |
|
|
|
|
|
|
|
|
|
|
|
async configureServer(vite) { |
|
return await dev(vite, vite_config, svelte_config); |
|
}, |
|
|
|
|
|
|
|
|
|
|
|
configurePreviewServer(vite) { |
|
return preview(vite, vite_config, svelte_config); |
|
}, |
|
|
|
|
|
|
|
|
|
buildStart() { |
|
if (secondary_build_started) return; |
|
|
|
if (is_build) { |
|
if (!vite_config.build.watch) { |
|
rimraf(out); |
|
} |
|
mkdirp(out); |
|
} |
|
}, |
|
|
|
renderChunk(code, chunk) { |
|
if (code.includes('__SVELTEKIT_TRACK__')) { |
|
return { |
|
code: code.replace(/__SVELTEKIT_TRACK__\('(.+?)'\)/g, (_, label) => { |
|
(tracked_features[chunk.name + '.js'] ??= []).push(label); |
|
|
|
return `/* track ${label} */`; |
|
}), |
|
map: null |
|
}; |
|
} |
|
}, |
|
|
|
generateBundle() { |
|
if (vite_config.build.ssr) return; |
|
|
|
this.emitFile({ |
|
type: 'asset', |
|
fileName: `${kit.appDir}/version.json`, |
|
source: s({ version: kit.version.name }) |
|
}); |
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
writeBundle: { |
|
sequential: true, |
|
async handler(_options) { |
|
if (secondary_build_started) return; |
|
|
|
const verbose = vite_config.logLevel === 'info'; |
|
const log = logger({ verbose }); |
|
|
|
|
|
const server_manifest = JSON.parse(read(`${out}/server/${vite_config.build.manifest}`)); |
|
|
|
|
|
const build_data = { |
|
app_dir: kit.appDir, |
|
app_path: `${kit.paths.base.slice(1)}${kit.paths.base ? '/' : ''}${kit.appDir}`, |
|
manifest_data, |
|
out_dir: out, |
|
service_worker: service_worker_entry_file ? 'service-worker.js' : null, |
|
client: null, |
|
server_manifest |
|
}; |
|
|
|
const manifest_path = `${out}/server/manifest-full.js`; |
|
fs.writeFileSync( |
|
manifest_path, |
|
`export const manifest = ${generate_manifest({ |
|
build_data, |
|
relative_path: '.', |
|
routes: manifest_data.routes |
|
})};\n` |
|
); |
|
|
|
|
|
log.info('Analysing routes'); |
|
|
|
build_server_nodes(out, kit, manifest_data, server_manifest, null, null); |
|
|
|
const metadata = await analyse({ |
|
manifest_path, |
|
manifest_data, |
|
server_manifest, |
|
tracked_features, |
|
env: { ...env.private, ...env.public } |
|
}); |
|
|
|
log.info('Building app'); |
|
|
|
|
|
write_client_manifest( |
|
kit, |
|
manifest_data, |
|
`${kit.outDir}/generated/client-optimized`, |
|
metadata.nodes |
|
); |
|
|
|
secondary_build_started = true; |
|
|
|
const { output } = ( |
|
await vite.build({ |
|
configFile: vite_config.configFile, |
|
|
|
mode: vite_config_env.mode, |
|
logLevel: vite_config.logLevel, |
|
clearScreen: vite_config.clearScreen, |
|
build: { |
|
minify: initial_config.build?.minify, |
|
assetsInlineLimit: vite_config.build.assetsInlineLimit, |
|
sourcemap: vite_config.build.sourcemap |
|
}, |
|
optimizeDeps: { |
|
force: vite_config.optimizeDeps.force |
|
} |
|
}) |
|
); |
|
|
|
copy( |
|
`${out}/server/${kit.appDir}/immutable/assets`, |
|
`${out}/client/${kit.appDir}/immutable/assets` |
|
); |
|
|
|
|
|
const client_manifest = JSON.parse(read(`${out}/client/${vite_config.build.manifest}`)); |
|
|
|
const deps_of = (f) => |
|
find_deps(client_manifest, posixify(path.relative('.', f)), false); |
|
const start = deps_of(`${runtime_directory}/client/entry.js`); |
|
const app = deps_of(`${kit.outDir}/generated/client-optimized/app.js`); |
|
|
|
build_data.client = { |
|
start: start.file, |
|
app: app.file, |
|
imports: [...start.imports, ...app.imports], |
|
stylesheets: [...start.stylesheets, ...app.stylesheets], |
|
fonts: [...start.fonts, ...app.fonts], |
|
uses_env_dynamic_public: output.some( |
|
(chunk) => chunk.type === 'chunk' && chunk.modules[env_dynamic_public] |
|
) |
|
}; |
|
|
|
const css = output.filter( |
|
|
|
(value) => value.type === 'asset' && value.fileName.endsWith('.css') |
|
); |
|
|
|
|
|
fs.writeFileSync( |
|
manifest_path, |
|
`export const manifest = ${generate_manifest({ |
|
build_data, |
|
relative_path: '.', |
|
routes: manifest_data.routes |
|
})};\n` |
|
); |
|
|
|
|
|
build_server_nodes(out, kit, manifest_data, server_manifest, client_manifest, css); |
|
|
|
|
|
const { prerendered, prerender_map } = await prerender({ |
|
out, |
|
manifest_path, |
|
metadata, |
|
verbose, |
|
env: { ...env.private, ...env.public } |
|
}); |
|
|
|
|
|
fs.writeFileSync( |
|
`${out}/server/manifest.js`, |
|
`export const manifest = ${generate_manifest({ |
|
build_data, |
|
relative_path: '.', |
|
routes: manifest_data.routes.filter((route) => prerender_map.get(route.id) !== true) |
|
})};\n` |
|
); |
|
|
|
if (service_worker_entry_file) { |
|
if (kit.paths.assets) { |
|
throw new Error('Cannot use service worker alongside config.kit.paths.assets'); |
|
} |
|
|
|
log.info('Building service worker'); |
|
|
|
await build_service_worker( |
|
out, |
|
kit, |
|
vite_config, |
|
manifest_data, |
|
service_worker_entry_file, |
|
prerendered, |
|
client_manifest |
|
); |
|
} |
|
|
|
|
|
|
|
finalise = async () => { |
|
console.log( |
|
`\nRun ${colors |
|
.bold() |
|
.cyan('npm run preview')} to preview your production build locally.` |
|
); |
|
|
|
if (kit.adapter) { |
|
const { adapt } = await import('../../core/adapt/index.js'); |
|
await adapt( |
|
svelte_config, |
|
build_data, |
|
metadata, |
|
prerendered, |
|
prerender_map, |
|
log, |
|
vite_config |
|
); |
|
} else { |
|
console.log(colors.bold().yellow('\nNo adapter specified')); |
|
|
|
const link = colors.bold().cyan('https://kit.svelte.dev/docs/adapters'); |
|
console.log( |
|
`See ${link} to learn how to configure your app to run on the platform of your choosing` |
|
); |
|
} |
|
|
|
secondary_build_started = false; |
|
}; |
|
} |
|
}, |
|
|
|
|
|
|
|
|
|
closeBundle: { |
|
sequential: true, |
|
async handler() { |
|
if (!vite_config.build.ssr) return; |
|
await finalise?.(); |
|
} |
|
} |
|
}; |
|
|
|
return [plugin_setup, plugin_virtual_modules, plugin_guard, plugin_compile]; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function warn_overridden_config(config, resolved_config) { |
|
const overridden = find_overridden_config(config, resolved_config, enforced_config, '', []); |
|
|
|
if (overridden.length > 0) { |
|
console.error( |
|
colors.bold().red('The following Vite config options will be overridden by SvelteKit:') + |
|
overridden.map((key) => `\n - ${key}`).join('') |
|
); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function find_overridden_config(config, resolved_config, enforced_config, path, out) { |
|
if (config == null || resolved_config == null) { |
|
return out; |
|
} |
|
|
|
for (const key in enforced_config) { |
|
if (typeof config === 'object' && key in config && key in resolved_config) { |
|
const enforced = enforced_config[key]; |
|
|
|
if (enforced === true) { |
|
if (config[key] !== resolved_config[key]) { |
|
out.push(path + key); |
|
} |
|
} else { |
|
find_overridden_config(config[key], resolved_config[key], enforced, path + key + '.', out); |
|
} |
|
} |
|
} |
|
return out; |
|
} |
|
|
|
|
|
|
|
|
|
const create_service_worker_module = (config) => dedent` |
|
if (typeof self === 'undefined' || self instanceof ServiceWorkerGlobalScope === false) { |
|
throw new Error('This module can only be imported inside a service worker'); |
|
} |
|
|
|
export const build = []; |
|
export const files = [ |
|
${create_assets(config) |
|
.filter((asset) => config.kit.serviceWorker.files(asset.file)) |
|
.map((asset) => `${s(`${config.kit.paths.base}/${asset.file}`)}`) |
|
.join(',\n')} |
|
]; |
|
export const prerendered = []; |
|
export const version = ${s(config.kit.version.name)}; |
|
`; |
|
|