Skip to content

feat!: vite 6 support #1020

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

Merged
merged 16 commits into from
Nov 21, 2024
31 changes: 22 additions & 9 deletions packages/vite-plugin-svelte/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ import { saveSvelteMetadata } from './utils/optimizer.js';
import { VitePluginSvelteCache } from './utils/vite-plugin-svelte-cache.js';
import { loadRaw } from './utils/load-raw.js';
import * as svelteCompiler from 'svelte/compiler';
import {
VITE_CLIENT_RESOLVE_CONDITIONS,
VITE_SERVER_RESOLVE_CONDITIONS
} from './utils/constants.js';

/**
* @param {Partial<import('./public.d.ts').Options>} [inlineOptions]
Expand Down Expand Up @@ -67,14 +63,31 @@ export function svelte(inlineOptions) {
log.debug('additional vite config', extraViteConfig, 'config');
return extraViteConfig;
},
// @ts-ignore Allow exist in vite 6
configEnvironment(name, config) {

// @ts-ignore This hook only works in Vite 6
async configEnvironment(name, config, opts) {
config.resolve ??= {};

// Emulate Vite default fallback for `resolve.mainFields` if not set
if (config.resolve.mainFields == null) {
// These exports only exist in Vite 6
const { defaultClientMainFields, defaultServerMainFields } = await import('vite');
if (name === 'client' || opts.isSsrTargetWebworker) {
config.resolve.mainFields = [...defaultClientMainFields];
} else {
config.resolve.mainFields = [...defaultServerMainFields];
}
}
config.resolve.mainFields.unshift('svelte');

// Emulate Vite default fallback for `resolve.conditions` if not set
if (config.resolve.conditions == null) {
if (name === 'client') {
config.resolve.conditions = [...VITE_CLIENT_RESOLVE_CONDITIONS];
// These exports only exist in Vite 6
const { defaultClientConditions, defaultServerConditions } = await import('vite');
if (name === 'client' || opts.isSsrTargetWebworker) {
Copy link
Member

Choose a reason for hiding this comment

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

is name === 'client' a good way to check this? that would assume there can only be one client environment in an app.

Copy link
Member

Choose a reason for hiding this comment

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

what if there was a tauri app and a web app at the same time, or two different clients?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah true, I think it should check the consumer here, which is the same as Vite internally.

Copy link
Member

Choose a reason for hiding this comment

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

is that a helper vite should expose?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure if it's needed imo

Copy link
Member

Choose a reason for hiding this comment

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

well how are others going to use these exposed constants then? you'll always want the ones applicable to the environment you are in, no?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not really sure what you mean. Do you have a pseudocode in mind for this?

Copy link
Member

Choose a reason for hiding this comment

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

if vite-plugin-svelte needs to check consumer (where exactly is that?) to decide which of the two constants to pick, wouldn't other plugins have to do the same? at this point it would be better to have a shared place for that logic.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've already updated the code to use consumer, it is the way Vite wants plugins to do to checks for client or server-based environments. You can get that from config.consumer

Copy link
Member Author

Choose a reason for hiding this comment

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

Looks like I need a combination of config.consumer === 'client' and name === 'client' checks to work, since config.consumer could be undefined but it's documented to fallback to consumer = 'client' if name is 'client'

config.resolve.conditions = [...defaultClientConditions];
} else {
config.resolve.conditions = [...VITE_SERVER_RESOLVE_CONDITIONS];
config.resolve.conditions = [...defaultServerConditions];
}
}
config.resolve.conditions.push('svelte');
Expand Down
5 changes: 0 additions & 5 deletions packages/vite-plugin-svelte/src/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@ import { createRequire } from 'node:module';

export const VITE_RESOLVE_MAIN_FIELDS = ['browser', 'module', 'jsnext:main', 'jsnext'];

// These two are required for Vite 6 only, as specifying conditions will remove the default ones,
// like the `mainFields` option. Vite 6 is working on exposing these which we can use later.
export const VITE_CLIENT_RESOLVE_CONDITIONS = ['module', 'browser', 'development|production'];
export const VITE_SERVER_RESOLVE_CONDITIONS = ['module', 'node', 'development|production'];

export const SVELTE_RESOLVE_MAIN_FIELDS = ['svelte'];

export const SVELTE_IMPORTS = Object.entries(
Expand Down
22 changes: 12 additions & 10 deletions packages/vite-plugin-svelte/src/utils/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,22 +334,24 @@ function resolveViteRoot(viteConfig) {
* @returns {Promise<Partial<import('vite').UserConfig>>}
*/
export async function buildExtraViteConfig(options, config) {
// make sure we only readd vite default mainFields when no other plugin has changed the config already
// see https://github.com/sveltejs/vite-plugin-svelte/issues/581
if (!config.resolve) {
config.resolve = {};
// `resolve.mainFields` override the defaults if set, but we want to extend it, so we directly mutate here.
// We only do so for Vite 5 and below, as in Vite 6, `resolve.mainFields` only apply to the client env,
// so we use the `configEnvironment` hook to set it up instead.
if (!isVite6) {
config.resolve ??= {};
config.resolve.mainFields = [
...SVELTE_RESOLVE_MAIN_FIELDS,
...(config.resolve.mainFields ?? VITE_RESOLVE_MAIN_FIELDS)
];
}
config.resolve.mainFields = [
...SVELTE_RESOLVE_MAIN_FIELDS,
...(config.resolve.mainFields ?? VITE_RESOLVE_MAIN_FIELDS)
];

/** @type {Partial<import('vite').UserConfig>} */
const extraViteConfig = {
resolve: {
dedupe: [...SVELTE_IMPORTS],
// In Vite 6, we need to provide the default conditions too as it now replaces the default,
// instead of extending it. We set undefined here and extend it in the `configEnvironment` hook instead.
// In Vite 6, conditions now override the defaults instead of extending. `resolve.conditions`
// also only apply to the client env, so we use the `configEnvironment` hook to set it up
// instead, so here we set to `undefined` to skip it.
conditions: isVite6 ? undefined : [...SVELTE_EXPORT_CONDITIONS]
}
// this option is still awaiting a PR in vite to be supported
Expand Down
Loading