diff --git a/.changeset/workspace-root-solid-pkgs.md b/.changeset/workspace-root-solid-pkgs.md new file mode 100644 index 0000000..53555af --- /dev/null +++ b/.changeset/workspace-root-solid-pkgs.md @@ -0,0 +1,5 @@ +--- +'@solidjs/vite-plugin': patch +--- + +Packages with a `solid` export condition that are declared only in the workspace root's `package.json` are now inlined for projects in that workspace. Before, Vitest loaded them with Node and failed with `Unknown file extension ".jsx"` (#157). diff --git a/examples/start-ssr/test/run.mjs b/examples/start-ssr/test/run.mjs index e6a3051..1c24e7f 100644 --- a/examples/start-ssr/test/run.mjs +++ b/examples/start-ssr/test/run.mjs @@ -6672,6 +6672,80 @@ async function runVitestMode() { `empty root: ${JSON.stringify(emptySetupFiles)}, example root: ${JSON.stringify(exampleSetupFiles)}`, ); + // A framework package (one with a `solid` export condition) that only the + // workspace root's package.json declares must still be inlined for a + // project in that workspace (#157). The crawl used to read only the + // project's own package.json, so vitest left the package external and + // Node failed on its `.jsx` files with `Unknown file extension ".jsx"`. + // The fixture is a workspace outside the repo: the root declares + // `fake-solid-lib`, and the project `packages/app` declares nothing. + const workspaceDir = path.join(os.tmpdir(), `solid-vite-plugin-workspace-${process.pid}`); + const appDir = path.join(workspaceDir, 'packages', 'app'); + const libDir = path.join(workspaceDir, 'node_modules', 'fake-solid-lib'); + const noExternalProbe = ` + import { resolveConfig } from 'vite'; + import solid from '@solidjs/vite-plugin'; + const resolved = await resolveConfig( + { root: process.argv[1], mode: 'test', configFile: false, logLevel: 'silent', plugins: [solid()] }, + 'serve', + ); + console.log(JSON.stringify(resolved.environments.ssr.resolve.noExternal)); + `; + let workspaceNoExternal; + let workspaceError = ''; + try { + rmSync(workspaceDir, { recursive: true, force: true }); + mkdirSync(appDir, { recursive: true }); + mkdirSync(libDir, { recursive: true }); + writeFileSync( + path.join(workspaceDir, 'package.json'), + JSON.stringify({ + name: 'workspace', + private: true, + workspaces: ['packages/*'], + dependencies: { 'fake-solid-lib': '1.0.0' }, + }), + ); + writeFileSync(path.join(appDir, 'package.json'), '{ "name": "app", "private": true }\n'); + writeFileSync( + path.join(libDir, 'package.json'), + JSON.stringify({ + name: 'fake-solid-lib', + version: '1.0.0', + type: 'module', + exports: { '.': { solid: './index.jsx', default: './index.js' } }, + }), + ); + writeFileSync(path.join(libDir, 'index.jsx'), 'export const Lib = () =>
lib
;\n'); + writeFileSync(path.join(libDir, 'index.js'), 'export const Lib = () => null;\n'); + workspaceNoExternal = JSON.parse( + execFileSync(process.execPath, ['--input-type=module', '-e', noExternalProbe, '--', appDir], { + cwd: exampleDir, + stdio: ['ignore', 'pipe', 'pipe'], + timeout: 60000, + }) + .toString() + .trim(), + ); + } catch (e) { + workspaceError = String(e.stderr || e); + } finally { + rmSync(workspaceDir, { recursive: true, force: true }); + } + const workspacePass = + !workspaceError && + Array.isArray(workspaceNoExternal) && + workspaceNoExternal.includes('fake-solid-lib'); + record( + mode, + 'workspace-root-pkgs', + 'framework packages declared only in the workspace root are inlined for a workspace project', + workspacePass, + workspacePass + ? undefined + : workspaceError || `noExternal: ${JSON.stringify(workspaceNoExternal)}`, + ); + // Vitest passes the `ssr` environment's conditions to Node as // `--conditions` for the packages it leaves external. A jsdom run used to // put `browser` there, so Node-only packages failed to load: `msw/node` diff --git a/src/index.ts b/src/index.ts index 2ed157f..dff0321 100644 --- a/src/index.ts +++ b/src/index.ts @@ -66,6 +66,7 @@ import { defaultClientConditions, defaultExternalConditions, defaultServerConditions, + searchForWorkspaceRoot, transformWithOxc, } from 'vite'; import { getEnvironmentConsumer, isRunnableEnvironment } from './environment.js'; @@ -1543,6 +1544,36 @@ export default function solidPlugin(options: Partial