summaryrefslogtreecommitdiff
path: root/packages/integrations/solid/src/index.ts
blob: deab40fd07a0e0d737517190b1b91d4e1db88b5c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import type {
	AstroIntegration,
	AstroIntegrationLogger,
	AstroRenderer,
	ContainerRenderer,
} from 'astro';
import type { PluginOption, UserConfig } from 'vite';
import solid, { type Options as ViteSolidPluginOptions } from 'vite-plugin-solid';

// TODO: keep in sync with https://github.com/thetarnav/solid-devtools/blob/main/packages/main/src/vite/index.ts#L7
type DevtoolsPluginOptions = {
	/** Add automatic name when creating signals, memos, stores, or mutables */
	autoname?: boolean;
	locator?:
		| boolean
		| {
				/** Choose in which IDE the component source code should be revealed. */
				targetIDE?: string;
				/**
				 * Holding which key should enable the locator overlay?
				 * @default 'Alt'
				 */
				key?: string;
				/** Inject location attributes to jsx templates */
				jsxLocation?: boolean;
				/** Inject location information to component declarations */
				componentLocation?: boolean;
		  };
};
type DevtoolsPlugin = (_options?: DevtoolsPluginOptions) => PluginOption;

async function getDevtoolsPlugin(logger: AstroIntegrationLogger, retrieve: boolean) {
	if (!retrieve) {
		return null;
	}

	try {
		// @ts-ignore
		return (await import('solid-devtools/vite')).default as DevtoolsPlugin;
	} catch (_) {
		logger.warn(
			'Solid Devtools requires `solid-devtools` as a peer dependency, add it to your project.',
		);
		return null;
	}
}

function getViteConfiguration(
	{ include, exclude }: Options,
	devtoolsPlugin: DevtoolsPlugin | null,
) {
	const config: UserConfig = {
		optimizeDeps: {
			include: ['@astrojs/solid-js/client.js'],
			exclude: ['@astrojs/solid-js/server.js'],
		},
		plugins: [solid({ include, exclude, ssr: true })],
	};

	if (devtoolsPlugin) {
		config.plugins?.push(devtoolsPlugin({ autoname: true }));
	}

	return config;
}

function getRenderer(): AstroRenderer {
	return {
		name: '@astrojs/solid-js',
		clientEntrypoint: '@astrojs/solid-js/client.js',
		serverEntrypoint: '@astrojs/solid-js/server.js',
	};
}

export function getContainerRenderer(): ContainerRenderer {
	return {
		name: '@astrojs/solid',
		serverEntrypoint: '@astrojs/solid-js/server.js',
	};
}

export interface Options extends Pick<ViteSolidPluginOptions, 'include' | 'exclude'> {
	devtools?: boolean;
}

export default function (options: Options = {}): AstroIntegration {
	return {
		name: '@astrojs/solid-js',
		hooks: {
			'astro:config:setup': async ({
				command,
				addRenderer,
				updateConfig,
				injectScript,
				logger,
			}) => {
				const devtoolsPlugin = await getDevtoolsPlugin(
					logger,
					!!options.devtools && command === 'dev',
				);

				addRenderer(getRenderer());
				updateConfig({
					vite: getViteConfiguration(options, devtoolsPlugin),
				});

				if (devtoolsPlugin) {
					injectScript('page', 'import "solid-devtools";');
				}
			},
			'astro:config:done': ({ logger, config }) => {
				const knownJsxRenderers = ['@astrojs/react', '@astrojs/preact', '@astrojs/solid-js'];
				const enabledKnownJsxRenderers = config.integrations.filter((renderer) =>
					knownJsxRenderers.includes(renderer.name),
				);

				if (enabledKnownJsxRenderers.length > 1 && !options.include && !options.exclude) {
					logger.warn(
						'More than one JSX renderer is enabled. This will lead to unexpected behavior unless you set the `include` or `exclude` option. See https://docs.astro.build/en/guides/integrations-guide/solid-js/#combining-multiple-jsx-frameworks for more information.',
					);
				}
			},
		},
	};
}