async function clientConfig(config, env) {
	const { source, src } = config;
	const { isProd } = env;
	const asyncLoader = require.resolve('@preact/async-loader');

	let swInjectManifest = [];
	if (config.sw) {
		let swPath = join(__dirname, '..', '..', '..', 'sw', 'sw.js');
		const userSwPath = join(src, 'sw.js');
		if (existsSync(userSwPath)) {
			swPath = userSwPath;
		} else {
			warn(`Could not find sw.js in ${src}. Using the default service worker.`);
		}

		swInjectManifest.push(
			new InjectManifest({
				swSrc: swPath,
				include: [
					/200\.html$/,
					/(?<!polyfills)\.js$/,
					/\.css$/,
					/\.(png|jpg|svg|gif|webp|avif)$/,
				],
			})
		);
	}

	let copyPatterns = [
		existsSync(source('manifest.json')) && { from: 'manifest.json' },
		// copy any static files
		existsSync(source('assets')) && { from: 'assets', to: 'assets' },
		// copy sw-debug
		!isProd && {
			from: resolve(__dirname, '../../resources/sw-debug.js'),
			to: 'sw-debug.js',
		},
		// copy files from static to build directory
		existsSync(source('static')) && {
			from: resolve(source('static')),
			to: '.',
		},
	].filter(Boolean);

	return {
		entry: {
			bundle: resolve(__dirname, './../entry'),
			'dom-polyfills': resolve(__dirname, './polyfills'),
		},
		output: {
			path: config.dest,
			publicPath: '/',
			filename: isProd ? '[name].[chunkhash:5].js' : '[name].js',
			chunkFilename: '[name].chunk.[chunkhash:5].js',
		},

		resolveLoader: {
			alias: {
				async: asyncLoader,
			},
		},

		// automatic async components :)
		module: {
			rules: [
				{
					test: /\.[jt]sx?$/,
					include: [
						filter(source('routes') + '/{*,*/index}.{js,jsx,ts,tsx}'),
						filter(
							source('components') +
								'/{routes,async}/{*,*/index}.{js,jsx,ts,tsx}'
						),
					],
					loader: asyncLoader,
					options: {
						name(filename) {
							filename = normalizePath(filename);
							let relative = filename.replace(normalizePath(src), '');
							if (!relative.includes('/routes/')) return false;
							return 'route-' + cleanFilename(relative);
						},
						formatName(filename) {
							filename = normalizePath(filename);
							let relative = filename.replace(normalizePath(source('.')), '');
							return cleanFilename(relative);
						},
					},
				},
			],
		},

		plugins: [
			new webpack.DefinePlugin({
				'process.env.ADD_SW': config.sw,
				'process.env.PRERENDER': config.prerender,
			}),
			...(await renderHTMLPlugin(config, env)),
			copyPatterns.length !== 0 &&
				new CopyWebpackPlugin({
					patterns: copyPatterns,
				}),
			...swInjectManifest,
		].filter(Boolean),
	};
}
@param {import('../../../types').Env} env
@returns {Promise<import('webpack').Configuration>}