diff --git a/.changeset/vite-9-environment-hooks.md b/.changeset/vite-9-environment-hooks.md new file mode 100644 index 0000000..c434fcd --- /dev/null +++ b/.changeset/vite-9-environment-hooks.md @@ -0,0 +1,5 @@ +--- +'@solidjs/vite-plugin': patch +--- + +Add Vite 9 forward compatibility by using the per-environment consumer in plugin hooks and accepting Vite 9 as a peer. diff --git a/examples/vite-8/vite.config.ts b/examples/vite-8/vite.config.ts index f612fbe..b91b775 100644 --- a/examples/vite-8/vite.config.ts +++ b/examples/vite-8/vite.config.ts @@ -2,6 +2,9 @@ import { defineConfig } from 'vite'; import solidPlugin from '@solidjs/vite-plugin'; export default defineConfig({ + future: { + removePluginHookSsrArgument: 'warn', + }, plugins: [ { name: 'simulate-eliminated-lazy-importer', diff --git a/package.json b/package.json index 5ba4ce8..b7ab1b3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@solidjs/vite-plugin", "version": "3.0.0-next.30", - "description": "solid-js integration plugin for vite 6/7/8", + "description": "solid-js integration plugin for Vite", "type": "module", "files": [ "dist", @@ -88,7 +88,7 @@ "@solidjs/web": "^2.0.0-rc.0", "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.*", "solid-js": "^2.0.0-rc.0", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" }, "peerDependenciesMeta": { "@testing-library/jest-dom": { diff --git a/scripts/test-examples.ts b/scripts/test-examples.ts index 235c0df..5718a99 100644 --- a/scripts/test-examples.ts +++ b/scripts/test-examples.ts @@ -3,6 +3,8 @@ import { promisify } from 'node:util'; const execAsync = promisify(exec); const examples = ['vite-6', 'vite-7', 'vite-8']; +const pluginHookSsrDeprecation = + "Plugin hook `options.ssr` is replaced with `this.environment.config.consumer === 'server'`."; const PORT = 4173; const TEST_TIMEOUT = 5 * 60 * 1000; // 5 minutes const cypressEnv = { ...process.env, ELECTRON_RUN_AS_NODE: undefined }; @@ -29,7 +31,10 @@ async function runExample(example) { try { // Install and build await execAsync('pnpm install', { cwd: examplePath }); - await execAsync('pnpm run build', { cwd: examplePath }); + const { stdout, stderr } = await execAsync('pnpm run build', { cwd: examplePath }); + if (`${stdout}\n${stderr}`.includes(pluginHookSsrDeprecation)) { + throw new Error(`Vite's deprecated plugin hook SSR argument was used in ${example}`); + } // Start preview server with timeout const server = spawn('pnpm', ['run', 'preview'], { cwd: examplePath }); diff --git a/src/environment.ts b/src/environment.ts index 3fe0d12..392b2d9 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -13,3 +13,13 @@ export function isRunnableEnvironment(environment: unknown): boolean { return !!environment && typeof environment === 'object' && 'runner' in environment; } + +export function getEnvironmentConsumer( + environment: unknown, + options?: { ssr?: boolean }, +): 'client' | 'server' { + const consumer = (environment as { config?: { consumer?: string } } | undefined)?.config + ?.consumer; + if (consumer === 'client' || consumer === 'server') return consumer; + return options?.ssr ? 'server' : 'client'; +} diff --git a/src/index.ts b/src/index.ts index f031ba8..88818a4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -26,7 +26,7 @@ export type { StartOptions }; import path from 'path'; import type { FilterPattern, Plugin, ViteDevServer } from 'vite'; import { createFilter, version } from 'vite'; -import { isRunnableEnvironment } from './environment.js'; +import { getEnvironmentConsumer, isRunnableEnvironment } from './environment.js'; import { crawlFrameworkPkgs } from 'vitefu'; const require = createRequire(import.meta.url); @@ -993,7 +993,7 @@ export default function solidPlugin(options: Partial = {}): Plugin[] { }, async transform(source, id, transformOptions) { - const isSsr = transformOptions && transformOptions.ssr; + const isSsr = getEnvironmentConsumer(this.environment, transformOptions) === 'server'; const currentFileExtension = getExtension(id); const extensionsToWatch = options.extensions || []; diff --git a/src/server-functions/index.ts b/src/server-functions/index.ts index 61346dd..836a486 100644 --- a/src/server-functions/index.ts +++ b/src/server-functions/index.ts @@ -17,7 +17,7 @@ import { type Plugin, type ViteDevServer, } from 'vite'; -import { isRunnableEnvironment } from '../environment.js'; +import { getEnvironmentConsumer, isRunnableEnvironment } from '../environment.js'; import { joinBase, sendWebResponse, webRequestFromNode } from '../http.js'; import { compile, type CompileOptions } from './compile.js'; import xxHash32 from './xxhash32.js'; @@ -487,7 +487,7 @@ export function serverFunctions( enforce: 'pre', resolveId(source, _importer, opts) { if (source === HANDLER_ID) { - if (!opts?.ssr) { + if (getEnvironmentConsumer(this.environment, opts) !== 'server') { this.error( `${HANDLER_ID} is server-only; import it from your server entry (SSR build).`, ); @@ -497,7 +497,7 @@ export function serverFunctions( return null; }, load(id, opts) { - if (id === HANDLER_ID && opts?.ssr) { + if (id === HANDLER_ID && getEnvironmentConsumer(this.environment, opts) === 'server') { const externalDev = this.environment.mode === 'dev' && (internal.externalDevServer || !isRunnableEnvironment(this.environment)); @@ -633,7 +633,7 @@ export function serverFunctions( return null; }, async load(id, opts) { - const mode = opts?.ssr ? 'server' : 'client'; + const mode = getEnvironmentConsumer(this.environment, opts); if (id === manifestId) { if (isBuild && mode === 'server') { // Merge the client build's persisted discoveries at load time, @@ -659,7 +659,7 @@ export function serverFunctions( name: 'solid:server-functions/compiler', enforce: 'pre', async transform(code, fileId, opts) { - const mode = opts?.ssr ? 'server' : 'client'; + const mode = getEnvironmentConsumer(this.environment, opts); const [id] = fileId.split('?'); if (!filter(id)) { return null; diff --git a/src/ssr/index.ts b/src/ssr/index.ts index ec9e4af..3154715 100644 --- a/src/ssr/index.ts +++ b/src/ssr/index.ts @@ -51,7 +51,7 @@ import { type PreviewServer, type ViteDevServer, } from 'vite'; -import { isRunnableEnvironment } from '../environment.js'; +import { getEnvironmentConsumer, isRunnableEnvironment } from '../environment.js'; import { collectDevStyles, collectDevStyleSources, @@ -1035,8 +1035,9 @@ export function startServe( return null; }, async load(id, opts) { + const consumer = getEnvironmentConsumer(this.environment, opts); if (id === HANDLER_ID) { - if (!opts?.ssr) { + if (consumer !== 'server') { this.error(`${HANDLER_ID} is server-only; import it from server code (SSR build).`); } const externalDev = @@ -1046,7 +1047,7 @@ export function startServe( return handlerModuleCode(externalDev); } if (id === RESOLVED_DEV_STYLES_ID) { - if (!opts?.ssr || this.environment.mode !== 'dev') { + if (consumer !== 'server' || this.environment.mode !== 'dev') { this.error(`${DEV_STYLES_ID} is only available to the development server handler.`); } return devStylesModuleCode(this.environment, (file) => this.addWatchFile(file));