Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions .changeset/ssr-webworker-worker-condition.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@solidjs/vite-plugin': patch
---

Server builds with `ssr.target: 'webworker'` now resolve the server builds of `solid-js` and `@solidjs/web`. The plugin adds the `worker` export condition to that environment, so `renderToString` and the other server APIs no longer resolve to their browser stubs (#153).
5 changes: 5 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1699,6 +1699,11 @@ export default function solidPlugin(options: Partial<Options> = {}): Plugin[] {
}
config.resolve.conditions = [
'solid',
// A server build with `ssr.target: 'webworker'` starts from Vite's
// client conditions, which select the browser builds of `solid-js`
// and `@solidjs/web`. Their `worker` export points at the server
// build, so add it for that environment. #153
...(opts.isSsrTargetWebworker ? ['worker'] : []),
...(replaceDev ? ['development'] : []),
// `development` nests above `observe` in the runtime's exports, so
// both may be present: dev serve keeps the dev build, builds get the
Expand Down
73 changes: 73 additions & 0 deletions src/ssr-webworker.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { mkdtemp, mkdir, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { build, type Rolldown } from 'vite';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import solidPlugin from './index.js';

let root: string;

beforeAll(async () => {
root = await mkdtemp(path.join(tmpdir(), 'solid-ssr-worker-'));
// Mirrors the export map of solid-js: `worker` selects the server build.
const solid = path.join(root, 'node_modules/solid-js');
await mkdir(solid, { recursive: true });
await writeFile(
path.join(solid, 'package.json'),
JSON.stringify({
name: 'solid-js',
version: '2.0.0',
type: 'module',
exports: {
'.': {
worker: './server.js',
browser: './browser.js',
node: './server.js',
default: './browser.js',
},
},
}),
);
await writeFile(path.join(solid, 'server.js'), 'export const build = "server";\n');
await writeFile(path.join(solid, 'browser.js'), 'export const build = "browser";\n');
await writeFile(path.join(root, 'package.json'), JSON.stringify({ name: 'app', type: 'module' }));
await writeFile(path.join(root, 'entry.js'), "export { build } from 'solid-js';\n");
});

afterAll(async () => {
await rm(root, { recursive: true, force: true });
});

async function buildSsr(ssr: Record<string, unknown>) {
const result = (await build({
root,
configFile: false,
logLevel: 'silent',
plugins: [solidPlugin({ ssr: true })],
ssr: { noExternal: true, ...ssr },
build: {
ssr: path.join(root, 'entry.js'),
write: false,
minify: false,
},
})) as Rolldown.RolldownOutput | Rolldown.RolldownOutput[];
const output = Array.isArray(result) ? result[0] : result;
return output.output
.filter((chunk): chunk is Rolldown.OutputChunk => chunk.type === 'chunk')
.map((chunk) => chunk.code)
.join('\n');
}

describe('ssr.target webworker', () => {
// #153: the webworker SSR build resolved the browser build of solid-js.
it('resolves the server build through the worker condition', async () => {
const code = await buildSsr({ target: 'webworker' });
expect(code).toContain('"server"');
expect(code).not.toContain('"browser"');
});

it('still resolves the server build for the node target', async () => {
const code = await buildSsr({});
expect(code).toContain('"server"');
});
});
Loading