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:
parent
899214298c
commit
a342a486c2
5 changed files with 153 additions and 47 deletions
18
.changeset/chatty-planes-bathe.md
Normal file
18
.changeset/chatty-planes-bathe.md
Normal 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.
|
5
examples/framework-svelte/svelte.config.js
Normal file
5
examples/framework-svelte/svelte.config.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { vitePreprocess } from '@astrojs/svelte';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
preprocess: vitePreprocess(),
|
||||||
|
};
|
|
@ -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`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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`.
|
||||||
|
|
|
@ -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 };
|
||||||
|
|
Loading…
Reference in a new issue