Skip to content

Commit

Permalink
Load a new Vite config object for the vite-node compiler (#1314)
Browse files Browse the repository at this point in the history
  • Loading branch information
mrm007 authored Feb 9, 2024
1 parent 9b4be60 commit e8a6850
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 34 deletions.
7 changes: 7 additions & 0 deletions .changeset/integration-plugins.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@vanilla-extract/integration': minor
---

A Vite config object can be passed to the vite-node compiler via the `viteConfig` option

`viteResolve` and `vitePlugins` options are deprecated and will be removed in a future version.
7 changes: 7 additions & 0 deletions .changeset/vite-plugin-plugins.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@vanilla-extract/vite-plugin': patch
---

Resolve and pass a new copy of the Vite config to the vite-node compiler

Previously, we were passing the same Vite config object to the vite-node compiler. This was causing compatibility issues with other plugins, such as Vitest and Remix.
37 changes: 25 additions & 12 deletions packages/integration/src/compiler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import assert from 'assert';
import { join, isAbsolute } from 'path';
import type { Adapter } from '@vanilla-extract/css';
import { transformCss } from '@vanilla-extract/css/transformCss';
import type { ModuleNode, InlineConfig as ViteConfig } from 'vite';
import type { ModuleNode, UserConfig as ViteUserConfig } from 'vite';

import type { IdentifierOption } from './types';
import { cssFileFilter } from './filters';
Expand Down Expand Up @@ -47,13 +48,15 @@ const scanModule = (entryModule: ModuleNode) => {
const createViteServer = async ({
root,
identifiers,
viteResolve,
vitePlugins,
}: Required<Omit<CreateCompilerOptions, 'cssImportSpecifier'>>) => {
viteConfig,
}: Required<
Pick<CreateCompilerOptions, 'root' | 'identifiers' | 'viteConfig'>
>) => {
const pkg = getPackageInfo(root);
const vite = await import('vite');

const server = await vite.createServer({
...viteConfig,
configFile: false,
root,
server: {
Expand All @@ -66,7 +69,6 @@ const createViteServer = async ({
ssr: {
noExternal: true,
},
resolve: viteResolve,
plugins: [
{
name: 'vanilla-extract-externalize',
Expand Down Expand Up @@ -98,7 +100,7 @@ const createViteServer = async ({
}
},
},
...vitePlugins,
...(viteConfig.plugins ?? []),
],
});

Expand Down Expand Up @@ -184,21 +186,32 @@ export interface CreateCompilerOptions {
root: string;
cssImportSpecifier?: (filePath: string) => string;
identifiers?: IdentifierOption;
viteResolve?: ViteConfig['resolve'];
vitePlugins?: ViteConfig['plugins'];
viteConfig?: ViteUserConfig;
/** @deprecated */
viteResolve?: ViteUserConfig['resolve'];
/** @deprecated */
vitePlugins?: ViteUserConfig['plugins'];
}
export const createCompiler = ({
root,
identifiers = 'debug',
cssImportSpecifier = (filePath) => filePath + '.vanilla.css',
viteResolve = {},
vitePlugins = [],
viteConfig,
viteResolve,
vitePlugins,
}: CreateCompilerOptions): Compiler => {
assert(
!(viteConfig && (viteResolve || vitePlugins)),
'viteConfig cannot be used with viteResolve or vitePlugins',
);

const vitePromise = createViteServer({
root,
identifiers,
viteResolve,
vitePlugins,
viteConfig: viteConfig ?? {
resolve: viteResolve,
plugins: vitePlugins,
},
});

const processVanillaFileCache = new Map<
Expand Down
55 changes: 34 additions & 21 deletions packages/vite-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import path from 'path';
import type {
Plugin,
ResolvedConfig,
UserConfig,
ConfigEnv,
ViteDevServer,
Rollup,
} from 'vite';
Expand Down Expand Up @@ -33,10 +33,11 @@ export function vanillaExtractPlugin({
unstable_mode: mode = 'emitCss',
}: Options = {}): Plugin {
let config: ResolvedConfig;
let userConfig: UserConfig;
let configEnv: ConfigEnv;
let server: ViteDevServer;
let packageName: string;
let compiler: Compiler | undefined;
const vitePromise = import('vite');

const getIdentOption = () =>
identifiers ?? (config.mode === 'production' ? 'short' : 'debug');
Expand Down Expand Up @@ -97,8 +98,8 @@ export function vanillaExtractPlugin({
configureServer(_server) {
server = _server;
},
config(viteUserConfig) {
userConfig = viteUserConfig;
config(_userConfig, _configEnv) {
configEnv = _configEnv;
return {
ssr: {
external: [
Expand All @@ -109,30 +110,42 @@ export function vanillaExtractPlugin({
},
};
},
async configResolved(resolvedConfig) {
config = resolvedConfig;
async configResolved(_resolvedConfig) {
config = _resolvedConfig;
packageName = getPackageInfo(config.root).name;

if (mode !== 'transform') {
const { loadConfigFromFile } = await vitePromise;
const configFile = await loadConfigFromFile(
{
command: config.command,
mode: config.mode,
isSsrBuild: configEnv.isSsrBuild,
},
config.configFile,
);

compiler = createCompiler({
root: config.root,
identifiers: getIdentOption(),
cssImportSpecifier: fileIdToVirtualId,
viteResolve: config.resolve,
vitePlugins: userConfig.plugins?.flat().filter(
(plugin) =>
typeof plugin === 'object' &&
plugin !== null &&
'name' in plugin &&
// Prevent an infinite loop where the compiler creates a new instance of the plugin,
// which creates a new compiler, which creates a new instance of the plugin, etc.
plugin.name !== 'vanilla-extract' &&
// Skip Vitest plugins
plugin.name !== 'vitest' &&
!plugin.name.startsWith('vitest:') &&
// Skip Remix because it throws an error if it's not loaded with a config file
plugin.name !== 'remix',
),
viteConfig: {
...configFile?.config,
plugins: configFile?.config.plugins?.flat().filter(
(plugin) =>
typeof plugin === 'object' &&
plugin !== null &&
'name' in plugin &&
// Prevent an infinite loop where the compiler creates a new instance of the plugin,
// which creates a new compiler, which creates a new instance of the plugin, etc.
plugin.name !== 'vanilla-extract' &&
// Skip Remix because it throws an error if it's not loaded with a config file.
// If it _is_ loaded with a config file, it will create an infinite loop because it
// also has a child compiler which uses the same mechanism to load the config file.
// https://github.com/remix-run/remix/pull/7990#issuecomment-1809356626
plugin.name !== 'remix',
),
},
});
}
},
Expand Down
3 changes: 3 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { PlaywrightTestConfig, devices } from '@playwright/test';

// Prevent Vite from attempting to clear the screen
process.stdout.isTTY = false;

const config: PlaywrightTestConfig = {
testMatch: '**/*.playwright.ts',
updateSnapshots: 'none',
Expand Down
4 changes: 3 additions & 1 deletion test-helpers/src/startFixture/vite.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path from 'path';
import http from 'http';

import { createServer, build, InlineConfig } from 'vite';
import type { InlineConfig } from 'vite';
import handler from 'serve-handler';
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
import inspect from 'vite-plugin-inspect';
Expand Down Expand Up @@ -54,6 +54,8 @@ export const startViteFixture = async (
},
};

const { createServer, build } = await import('vite');

if (mode === 'development') {
const server = await createServer(config);

Expand Down

0 comments on commit e8a6850

Please sign in to comment.