0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-16 21:46:22 -05:00

Refactor Svelte preprocess integration handling (#5901)

* Let user setup vitePreprocess

* Abstract function

* Add changeset

* Update svelte syntax

* Make fallback

* Fix docs

* Update changeset

* Fix types
This commit is contained in:
Bjorn Lu 2023-01-19 21:13:40 +08:00 committed by GitHub
parent 899214298c
commit a342a486c2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 153 additions and 47 deletions

View file

@ -0,0 +1,18 @@
---
'@astrojs/svelte': major
'astro': minor
---
The fallback Svelte preprocessor will only be applied if a custom `preprocess` option is not passed to the `svelte()` integration option, or in the `svelte.config.js` file.
To support IDE autocompletion, or if you're migrating from `@astrojs/svelte` v1, you can create a `svelte.config.js` file with:
```js
import { vitePreprocess } from '@astrojs/svelte';
export default {
preprocess: vitePreprocess(),
};
```
This file will also be generated by `astro add svelte` by default.

View file

@ -0,0 +1,5 @@
import { vitePreprocess } from '@astrojs/svelte';
export default {
preprocess: vitePreprocess(),
};

View file

@ -53,6 +53,13 @@ module.exports = {
}, },
plugins: [], plugins: [],
}\n`; }\n`;
const SVELTE_CONFIG_STUB = `\
import { vitePreprocess } from '@astrojs/svelte';
export default {
preprocess: vitePreprocess(),
};
`;
const OFFICIAL_ADAPTER_TO_IMPORT_MAP: Record<string, string> = { const OFFICIAL_ADAPTER_TO_IMPORT_MAP: Record<string, string> = {
netlify: '@astrojs/netlify/functions', netlify: '@astrojs/netlify/functions',
@ -114,37 +121,30 @@ export default async function add(names: string[], { cwd, flags, logging, teleme
switch (installResult) { switch (installResult) {
case UpdateResult.updated: { case UpdateResult.updated: {
if (integrations.find((integration) => integration.id === 'tailwind')) { if (integrations.find((integration) => integration.id === 'tailwind')) {
const possibleConfigFiles = [ await setupIntegrationConfig({
'./tailwind.config.cjs', root,
'./tailwind.config.mjs', logging,
'./tailwind.config.js', flags,
].map((p) => fileURLToPath(new URL(p, root))); integrationName: 'Tailwind',
let alreadyConfigured = false; possibleConfigFiles: [
for (const possibleConfigPath of possibleConfigFiles) { './tailwind.config.cjs',
if (existsSync(possibleConfigPath)) { './tailwind.config.mjs',
alreadyConfigured = true; './tailwind.config.js',
break; ],
} defaultConfigFile: './tailwind.config.cjs',
} defaultConfigContent: TAILWIND_CONFIG_STUB,
if (!alreadyConfigured) { });
info( }
logging, if (integrations.find((integration) => integration.id === 'svelte')) {
null, await setupIntegrationConfig({
`\n ${magenta( root,
`Astro will generate a minimal ${bold('./tailwind.config.cjs')} file.` logging,
)}\n` flags,
); integrationName: 'Svelte',
if (await askToContinue({ flags })) { possibleConfigFiles: ['./svelte.config.js', './svelte.config.cjs', './svelte.config.mjs'],
await fs.writeFile( defaultConfigFile: './svelte.config.js',
fileURLToPath(new URL('./tailwind.config.cjs', root)), defaultConfigContent: SVELTE_CONFIG_STUB,
TAILWIND_CONFIG_STUB, });
{ encoding: 'utf-8' }
);
debug('add', `Generated default ./tailwind.config.cjs file`);
}
} else {
debug('add', `Using existing Tailwind configuration`);
}
} }
break; break;
} }
@ -886,3 +886,43 @@ function getDiffContent(input: string, output: string): string | null {
return diffed; return diffed;
} }
async function setupIntegrationConfig(opts: {
root: URL;
logging: LogOptions;
flags: yargs.Arguments;
integrationName: string;
possibleConfigFiles: string[];
defaultConfigFile: string;
defaultConfigContent: string;
}) {
const possibleConfigFiles = opts.possibleConfigFiles.map((p) =>
fileURLToPath(new URL(p, opts.root))
);
let alreadyConfigured = false;
for (const possibleConfigPath of possibleConfigFiles) {
if (existsSync(possibleConfigPath)) {
alreadyConfigured = true;
break;
}
}
if (!alreadyConfigured) {
info(
opts.logging,
null,
`\n ${magenta(`Astro will generate a minimal ${bold(opts.defaultConfigFile)} file.`)}\n`
);
if (await askToContinue({ flags: opts.flags })) {
await fs.writeFile(
fileURLToPath(new URL(opts.defaultConfigFile, opts.root)),
opts.defaultConfigContent,
{
encoding: 'utf-8',
}
);
debug('add', `Generated default ${opts.defaultConfigFile} file`);
}
} else {
debug('add', `Using existing ${opts.integrationName} configuration`);
}
}

View file

@ -84,18 +84,44 @@ A few of the default options passed to the Svelte compiler are required to build
const defaultOptions = { const defaultOptions = {
emitCss: true, emitCss: true,
compilerOptions: { dev: isDev, hydratable: true }, compilerOptions: { dev: isDev, hydratable: true },
preprocess: [ preprocess: vitePreprocess()
preprocess({
less: true,
sass: { renderSync: true },
scss: { renderSync: true },
stylus: true,
typescript: true,
}),
],
}; };
``` ```
The `emitCss`, `compilerOptions.dev`, and `compilerOptions.hydratable` cannot be overridden. The `emitCss`, `compilerOptions.dev`, and `compilerOptions.hydratable` cannot be overridden.
Providing your own `preprocess` options **will** override the defaults - make sure to enable the preprocessor flags needed for your project. Providing your own `preprocess` options **will** override the defaults - make sure to enable the preprocessor flags needed for your project. For example,
```js
// astro.config.js
import svelte from '@astrojs/svelte';
export default {
integrations: [svelte({ preprocess: [] })],
};
```
and
```js
// svelte.config.js
export default {
preprocess: [],
};
```
Will override the default `preprocess` option. You can read the [`vitePreprocess` docs](https://github.com/sveltejs/vite-plugin-svelte/blob/HEAD/docs/preprocess.md) for more information of how it works.
## Intellisense for TypeScript
If you're using a preprocessor like TypeScript or SCSS in your Svelte files, you can create a `svelte.config.js` file with:
```js
import { vitePreprocess } from '@astrojs/svelte';
export default {
preprocess: vitePreprocess(),
};
```
So the Svelte IDE extension can correctly parse the Svelte files. This config file is added by default when you run `astro add svelte`.

View file

@ -2,6 +2,7 @@ import type { Options } from '@sveltejs/vite-plugin-svelte';
import { svelte, vitePreprocess } from '@sveltejs/vite-plugin-svelte'; import { svelte, vitePreprocess } from '@sveltejs/vite-plugin-svelte';
import type { AstroIntegration, AstroRenderer } from 'astro'; import type { AstroIntegration, AstroRenderer } from 'astro';
import type { UserConfig } from 'vite'; import type { UserConfig } from 'vite';
import { fileURLToPath } from 'url';
function getRenderer(): AstroRenderer { function getRenderer(): AstroRenderer {
return { return {
@ -11,16 +12,27 @@ function getRenderer(): AstroRenderer {
}; };
} }
async function svelteConfigHasPreprocess(root: URL) {
const svelteConfigFiles = ['./svelte.config.js', './svelte.config.cjs', './svelte.config.mjs'];
for (const file of svelteConfigFiles) {
const filePath = fileURLToPath(new URL(file, root));
try {
const config = (await import(filePath)).default;
return !!config.preprocess;
} catch {}
}
}
type ViteConfigurationArgs = { type ViteConfigurationArgs = {
isDev: boolean; isDev: boolean;
options?: Options | OptionsCallback; options?: Options | OptionsCallback;
root: URL;
}; };
function getViteConfiguration({ options, isDev }: ViteConfigurationArgs): UserConfig { async function getViteConfiguration({ options, isDev, root }: ViteConfigurationArgs): Promise<UserConfig> {
const defaultOptions: Partial<Options> = { const defaultOptions: Partial<Options> = {
emitCss: true, emitCss: true,
compilerOptions: { dev: isDev, hydratable: true }, compilerOptions: { dev: isDev, hydratable: true },
preprocess: [vitePreprocess()],
}; };
// Disable hot mode during the build // Disable hot mode during the build
@ -43,11 +55,13 @@ function getViteConfiguration({ options, isDev }: ViteConfigurationArgs): UserCo
// Always use dev and hydratable from defaults // Always use dev and hydratable from defaults
...defaultOptions.compilerOptions, ...defaultOptions.compilerOptions,
}, },
// Ignore default preprocessor if the user provided their own
preprocess: options.preprocess ?? defaultOptions.preprocess,
}; };
} }
if (!resolvedOptions.preprocess && !(await svelteConfigHasPreprocess(root))) {
resolvedOptions.preprocess = vitePreprocess();
}
return { return {
optimizeDeps: { optimizeDeps: {
include: ['@astrojs/svelte/client.js'], include: ['@astrojs/svelte/client.js'],
@ -63,15 +77,18 @@ export default function (options?: Options | OptionsCallback): AstroIntegration
name: '@astrojs/svelte', name: '@astrojs/svelte',
hooks: { hooks: {
// Anything that gets returned here is merged into Astro Config // Anything that gets returned here is merged into Astro Config
'astro:config:setup': ({ command, updateConfig, addRenderer }) => { 'astro:config:setup': async ({ command, updateConfig, addRenderer, config }) => {
addRenderer(getRenderer()); addRenderer(getRenderer());
updateConfig({ updateConfig({
vite: getViteConfiguration({ vite: await getViteConfiguration({
options, options,
isDev: command === 'dev', isDev: command === 'dev',
root: config.root,
}), }),
}); });
}, },
}, },
}; };
} }
export { vitePreprocess };