Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[docs] add JSDocs for Vite build process #5517

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/kit/src/vite/build/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ export function assets_base(config) {
}

/**
* vite.config.js will contain vite-plugin-svelte-kit, which kicks off the server and service
* worker builds in a hook. When running the server and service worker builds we must remove
* the SvelteKit plugin so that we do not kick off additional instances of these builds.
* @param {import('vite').UserConfig} config
*/
export function remove_svelte_kit(config) {
Expand Down
121 changes: 83 additions & 38 deletions packages/kit/src/vite/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ export function sveltekit() {
}

/**
* Returns the SvelteKit Vite plugin. Vite executes Rollup hooks as well as some of its own.
* Background reading is available at:
* - https://vitejs.dev/guide/api-plugin.html
* - https://rollupjs.org/guide/en/#plugin-development
*
* You can get an idea of the lifecycle by looking at the flow charts here:
* - https://rollupjs.org/guide/en/#build-hooks
* - https://rollupjs.org/guide/en/#output-generation-hooks
*
* @return {import('vite').Plugin}
*/
function kit() {
Expand Down Expand Up @@ -99,7 +108,7 @@ function kit() {
*/
let paths;

function create_client_config() {
function vite_client_config() {
/** @type {Record<string, string>} */
const input = {
// Put unchanging assets in immutable directory. We don't set that in the
Expand Down Expand Up @@ -128,9 +137,35 @@ function kit() {
});
}

/**
* @param {import('rollup').OutputAsset[]} assets
* @param {import('rollup').OutputChunk[]} chunks
*/
function client_build_info(assets, chunks) {
/** @type {import('vite').Manifest} */
const vite_manifest = JSON.parse(
fs.readFileSync(`${paths.client_out_dir}/manifest.json`, 'utf-8')
);

const entry_id = posixify(
path.relative(cwd, `${get_runtime_path(svelte_config.kit)}/client/start.js`)
);

return {
assets,
chunks,
entry: find_deps(vite_manifest, entry_id, false),
vite_manifest
};
}

return {
name: 'vite-plugin-svelte-kit',

/**
* Build the SvelteKit-provided Vite config to be merged with the user's vite.config.js file.
* @see https://vitejs.dev/guide/api-plugin.html#config
*/
async config(config, config_env) {
vite_config_env = config_env;
svelte_config = await load_config();
Expand All @@ -149,7 +184,7 @@ function kit() {

manifest_data = sync.all(svelte_config).manifest_data;

const new_config = create_client_config();
const new_config = vite_client_config();

warn_overridden_config(config, new_config);

Expand Down Expand Up @@ -195,10 +230,16 @@ function kit() {
return result;
},

/**
* Stores the final config.
*/
configResolved(config) {
vite_config = config;
},

/**
* Clears the output directories.
*/
buildStart() {
if (is_build) {
rimraf(paths.build_dir);
Expand All @@ -209,6 +250,11 @@ function kit() {
}
},

/**
* Vite builds a single bundle. We need three bundles: client, server, and service worker.
* The user's package.json scripts will invoke the Vite CLI to execute the client build. We
* then use this hook to kick off builds for the server and service worker.
*/
async writeBundle(_options, bundle) {
log = logger({
verbose: vite_config.logLevel === 'info'
Expand All @@ -219,36 +265,10 @@ function kit() {
JSON.stringify({ version: process.env.VITE_SVELTEKIT_APP_VERSION })
);

/** @type {import('rollup').OutputChunk[]} */
const chunks = [];
/** @type {import('rollup').OutputAsset[]} */
const assets = [];
for (const key of Object.keys(bundle)) {
// collect asset and output chunks
if (bundle[key].type === 'asset') {
assets.push(/** @type {import('rollup').OutputAsset} */ (bundle[key]));
} else {
chunks.push(/** @type {import('rollup').OutputChunk} */ (bundle[key]));
}
}

/** @type {import('vite').Manifest} */
const vite_manifest = JSON.parse(
fs.readFileSync(`${paths.client_out_dir}/manifest.json`, 'utf-8')
);

const entry_id = posixify(
path.relative(cwd, `${get_runtime_path(svelte_config.kit)}/client/start.js`)
);

const client = {
assets,
chunks,
entry: find_deps(vite_manifest, entry_id, false),
vite_manifest
};
const { assets, chunks } = collect_output(bundle);
log.info(`Client build completed. Wrote ${chunks.length} chunks and ${assets.length} assets`);

log.info('Building server');
const options = {
cwd,
config: svelte_config,
Expand All @@ -258,13 +278,9 @@ function kit() {
output_dir: paths.output_dir,
service_worker_entry_file: resolve_entry(svelte_config.kit.files.serviceWorker)
};

log.info('Building server');

const client = client_build_info(assets, chunks);
const server = await build_server(options, client);

process.env.SVELTEKIT_SERVER_BUILD_COMPLETED = 'true';

/** @type {import('types').BuildData} */
build_data = {
app_dir: svelte_config.kit.appDir,
Expand All @@ -283,6 +299,9 @@ function kit() {
})};\n`
);

process.env.SVELTEKIT_SERVER_BUILD_COMPLETED = 'true';
log.info('Prerendering');

const static_files = manifest_data.assets.map((asset) => posixify(asset.file));

const files = new Set([
Expand All @@ -298,8 +317,6 @@ function kit() {
}
});

log.info('Prerendering');

prerendered = await prerender({
config: svelte_config.kit,
entries: manifest_data.routes
Expand All @@ -324,6 +341,9 @@ function kit() {
);
},

/**
* Runs the adapter.
*/
async closeBundle() {
if (!is_build) {
return; // vite calls closeBundle when dev-server restarts, ignore that
Expand All @@ -341,22 +361,47 @@ function kit() {

if (svelte_config.kit.prerender.enabled) {
// this is necessary to close any open db connections, etc.
// TODO: prerender in a subprocess so we can exit in isolation
// TODO: prerender in a subprocess so we can exit in isolation and then remove this
// https://github.com/sveltejs/kit/issues/5306
process.exit(0);
}
},

/**
* Adds the SvelteKit middleware to do SSR in dev mode.
* @see https://vitejs.dev/guide/api-plugin.html#configureserver
*/
async configureServer(vite) {
return await dev(vite, vite_config, svelte_config);
},

/**
* Adds the SvelteKit middleware to do SSR in preview mode.
* @see https://vitejs.dev/guide/api-plugin.html#configurepreviewserver
*/
configurePreviewServer(vite) {
return preview(vite, svelte_config, vite_config.preview.https ? 'https' : 'http');
}
};
}

/** @param {import('rollup').OutputBundle} bundle */
function collect_output(bundle) {
/** @type {import('rollup').OutputChunk[]} */
const chunks = [];
/** @type {import('rollup').OutputAsset[]} */
const assets = [];
for (const key of Object.keys(bundle)) {
// collect asset and output chunks
if (bundle[key].type === 'asset') {
assets.push(/** @type {import('rollup').OutputAsset} */ (bundle[key]));
} else {
chunks.push(/** @type {import('rollup').OutputChunk} */ (bundle[key]));
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The key isn't used directly, might as well refactor it to Object.values while we're here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, we can also leverage TS control flow for discriminated unions and remove the type assertion.

return { assets, chunks };
}

/**
* @param {Record<string, any>} config
* @param {Record<string, any>} resolved_config
Expand Down