Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Svelte preprocess integration handling #5901

Merged
merged 8 commits into from
Jan 19, 2023
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
18 changes: 18 additions & 0 deletions .changeset/chatty-planes-bathe.md
Original file line number Diff line number Diff line change
@@ -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 changes: 5 additions & 0 deletions examples/framework-svelte/svelte.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { vitePreprocess } from '@astrojs/svelte';

export default {
preprocess: vitePreprocess(),
};
102 changes: 71 additions & 31 deletions packages/astro/src/core/add/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ module.exports = {
},
plugins: [],
}\n`;
const SVELTE_CONFIG_STUB = `\
import { vitePreprocess } from '@astrojs/svelte';

export default {
preprocess: vitePreprocess(),
};
`;

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

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`);
}
}
46 changes: 36 additions & 10 deletions packages/integrations/svelte/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,18 +84,44 @@ A few of the default options passed to the Svelte compiler are required to build
const defaultOptions = {
emitCss: true,
compilerOptions: { dev: isDev, hydratable: true },
preprocess: [
preprocess({
less: true,
sass: { renderSync: true },
scss: { renderSync: true },
stylus: true,
typescript: true,
}),
],
preprocess: vitePreprocess()
};
```

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`.
29 changes: 23 additions & 6 deletions packages/integrations/svelte/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Options } from '@sveltejs/vite-plugin-svelte';
import { svelte, vitePreprocess } from '@sveltejs/vite-plugin-svelte';
import type { AstroIntegration, AstroRenderer } from 'astro';
import type { UserConfig } from 'vite';
import { fileURLToPath } from 'url';

function getRenderer(): AstroRenderer {
return {
Expand All @@ -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 = {
isDev: boolean;
options?: Options | OptionsCallback;
root: URL;
};

function getViteConfiguration({ options, isDev }: ViteConfigurationArgs): UserConfig {
async function getViteConfiguration({ options, isDev, root }: ViteConfigurationArgs): Promise<UserConfig> {
const defaultOptions: Partial<Options> = {
emitCss: true,
compilerOptions: { dev: isDev, hydratable: true },
preprocess: [vitePreprocess()],
};

// Disable hot mode during the build
Expand All @@ -43,11 +55,13 @@ function getViteConfiguration({ options, isDev }: ViteConfigurationArgs): UserCo
// Always use dev and hydratable from defaults
...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 {
optimizeDeps: {
include: ['@astrojs/svelte/client.js'],
Expand All @@ -63,15 +77,18 @@ export default function (options?: Options | OptionsCallback): AstroIntegration
name: '@astrojs/svelte',
hooks: {
// 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());
updateConfig({
vite: getViteConfiguration({
vite: await getViteConfiguration({
options,
isDev: command === 'dev',
root: config.root,
}),
});
},
},
};
}

export { vitePreprocess };