Skip to content

Commit 04070c0

Browse files
matthewpbholmesdev
andauthored
Migrate to Vite 3 ⚡️ (#3570)
* Vite 3 test * deps: bump to Vite beta.1 * refactor: move to use optimizeDeps.force option * refactor: stub out new updateModuleInfo params * nit: remove comment on deprecated Vite feature * nit: remove comment on deprecated vite feature * hail mary: destroy all ssr external / noexternal! * fix: use new middlewareMode config settings * fix: resolve npm package paths for rollup input * wip: revert to unresolved. Issue reported! * sad refactor: use legacy devDepsScanner for component HMR * fix: add astro/components to noExternal for Code component * refactor: use ALWAYS_NOEXTERNAL array * refactor: add package.json to all test runners for noExternal error * deps: bump to latest vite 3 beta * wip: add package.json to smoke * fix: remove accidental "force true" on create-vite * refactor: write smoke package.json programmatically * refactor: add fontsource to noExternal * fix: only add to ssr.noExternal if present in project * wip: what if we just... didn't have a memory test * deps: bump to latest vite beta * Revert "wip: what if we just... didn't have a memory test" This reverts commit 173729d. * fix: add type check for plugin.name * feat: remove legacy.devDepsScanner. Vite 3 strat is now Vite 2.x strat! * fix: add ssr.noExternal to components ex * wip: ignore with-mdx starter * fix: add serviceEntryPoint to ssr.noExternal * temp: reset NODE_ENV on prod builds * fix: missing async tag * VITE 3 IS STABLE BABY * deps: bump svelte to vite 3 * deps: bump vue to vite 3 * fix: resolve plugins for proper sorting * sad fix: regex "export default" out of CSS ssr * chore: add TODO to understand sad fix * Revert "fix: resolve plugins for proper sorting" This reverts commit e67c194. * Revert "sad fix: regex "export default" out of CSS ssr" This reverts commit 721d40b. * fix: sort plugins WITHOUT resolveConfig * Revert "wip: ignore with-mdx starter" This reverts commit 7d4f733. * chore: revert memory test changes * chore: add nanostores/preact ot noexternal * chore: changeset * chore: changeset * deps: use Vite ^3.0.0 * fix: add back third party astro pkg scanner Co-authored-by: bholmesdev <hey@bholmes.dev>
1 parent 3753400 commit 04070c0

File tree

30 files changed

+338
-85
lines changed

30 files changed

+338
-85
lines changed

.changeset/thirty-beans-poke.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'astro': minor
3+
'@astrojs/image': minor
4+
'@astrojs/svelte': minor
5+
'@astrojs/vue': minor
6+
---
7+
8+
Bump to Vite 3!
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
import { defineConfig } from 'astro/config';
22

33
// https://astro.build/config
4-
export default defineConfig({});
4+
export default defineConfig({
5+
vite: {
6+
ssr: {
7+
noExternal: ['@example/my-component']
8+
},
9+
},
10+
});

packages/astro/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@
136136
"strip-ansi": "^7.0.1",
137137
"supports-esm": "^1.0.0",
138138
"tsconfig-resolver": "^3.0.1",
139-
"vite": "^2.9.14",
139+
"vite": "^3.0.0",
140140
"yargs-parser": "^21.0.1",
141141
"zod": "^3.17.3"
142142
},

packages/astro/src/core/build/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,9 @@ class AstroBuilder {
7373
mode: this.mode,
7474
server: {
7575
hmr: false,
76-
middlewareMode: 'ssr',
76+
middlewareMode: true,
7777
},
78+
appType: 'custom',
7879
},
7980
{ astroConfig: this.config, logging, mode: 'build' }
8081
);

packages/astro/src/core/build/page-data.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export async function collectPagesData(
5757
'build',
5858
`${colors.bold(
5959
route.component
60-
)} is taking a bit longer to import. This is common for larger "Astro.glob(...)" or "import.meta.globEager(...)" calls, for instance. Hang tight!`
60+
)} is taking a bit longer to import. This is common for larger "Astro.glob(...)" or "import.meta.glob(...)" calls, for instance. Hang tight!`
6161
);
6262
clearInterval(routeCollectionLogTimeout);
6363
}, 10000);

packages/astro/src/core/build/static-build.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { fileURLToPath } from 'url';
66
import * as vite from 'vite';
77
import { BuildInternals, createBuildInternals } from '../../core/build/internal.js';
88
import { prependForwardSlash } from '../../core/path.js';
9-
import { emptyDir, removeDir } from '../../core/util.js';
9+
import { emptyDir, removeDir, resolveDependency } from '../../core/util.js';
1010
import { runHookBuildSetup } from '../../integrations/index.js';
1111
import { rollupPluginAstroBuildCSS } from '../../vite-plugin-build-css/index.js';
1212
import type { ViteConfigWithSSR } from '../create-vite';
@@ -67,10 +67,12 @@ export async function staticBuild(opts: StaticBuildOptions) {
6767
const ssrResult = (await ssrBuild(opts, internals, pageInput)) as RollupOutput;
6868
info(opts.logging, 'build', dim(`Completed in ${getTimeStat(timer.ssr, performance.now())}.`));
6969

70-
const clientInput = new Set<string>([
70+
const rendererClientEntrypoints = opts.astroConfig._ctx.renderers.map((r) => r.clientEntrypoint).filter(a => typeof a === 'string') as string[]
71+
72+
const clientInput = new Set([
7173
...internals.discoveredHydratedComponents,
7274
...internals.discoveredClientOnlyComponents,
73-
...(astroConfig._ctx.renderers.map((r) => r.clientEntrypoint).filter((a) => a) as string[]),
75+
...rendererClientEntrypoints,
7476
...internals.discoveredScripts,
7577
]);
7678

@@ -167,7 +169,7 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp
167169
async function clientBuild(
168170
opts: StaticBuildOptions,
169171
internals: BuildInternals,
170-
input: Set<string>
172+
input: Set<string>,
171173
) {
172174
const { astroConfig, viteConfig } = opts;
173175
const timer = performance.now();

packages/astro/src/core/create-vite.ts

Lines changed: 49 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type { AstroConfig } from '../@types/astro';
22
import type { LogOptions } from './logger/core';
33

44
import fs from 'fs';
5-
import { builtinModules } from 'module';
65
import { fileURLToPath } from 'url';
76
import * as vite from 'vite';
87
import astroPostprocessVitePlugin from '../vite-plugin-astro-postprocess/index.js';
@@ -14,45 +13,47 @@ import astroIntegrationsContainerPlugin from '../vite-plugin-integrations-contai
1413
import jsxVitePlugin from '../vite-plugin-jsx/index.js';
1514
import markdownVitePlugin from '../vite-plugin-markdown/index.js';
1615
import astroScriptsPlugin from '../vite-plugin-scripts/index.js';
16+
import { resolveDependency } from './util.js';
17+
18+
// note: ssr is still an experimental API hence the type omission from `vite`
19+
export type ViteConfigWithSSR = vite.InlineConfig & { ssr?: vite.SSROptions };
20+
21+
interface CreateViteOptions {
22+
astroConfig: AstroConfig;
23+
logging: LogOptions;
24+
mode: 'dev' | 'build';
25+
}
1726

18-
// Some packages are just external, and that’s the way it goes.
19-
const ALWAYS_EXTERNAL = new Set([
20-
...builtinModules.map((name) => `node:${name}`),
21-
'@sveltejs/vite-plugin-svelte',
22-
'micromark-util-events-to-acorn',
23-
'@astrojs/markdown-remark',
24-
// in-lined for markdown modules
25-
'github-slugger',
26-
'node-fetch',
27-
'prismjs',
28-
'shiki',
29-
'unified',
30-
'whatwg-url',
31-
]);
3227
const ALWAYS_NOEXTERNAL = new Set([
3328
// This is only because Vite's native ESM doesn't resolve "exports" correctly.
3429
'astro',
30+
// Vite fails on nested `.astro` imports without bundling
31+
'astro/components',
3532
// Handle recommended nanostores. Only @nanostores/preact is required from our testing!
3633
// Full explanation and related bug report: https://github.com/withastro/astro/pull/3667
3734
'@nanostores/preact',
3835
]);
3936

40-
// note: ssr is still an experimental API hence the type omission from `vite`
41-
export type ViteConfigWithSSR = vite.InlineConfig & { ssr?: vite.SSROptions };
42-
43-
interface CreateViteOptions {
44-
astroConfig: AstroConfig;
45-
logging: LogOptions;
46-
mode: 'dev' | 'build';
37+
function getSsrNoExternalDeps(projectRoot: URL): string[] {
38+
let noExternalDeps = []
39+
for (const dep of ALWAYS_NOEXTERNAL) {
40+
try {
41+
resolveDependency(dep, projectRoot)
42+
noExternalDeps.push(dep)
43+
} catch {
44+
// ignore dependency if *not* installed / present in your project
45+
// prevents hard error from Vite!
46+
}
47+
}
48+
return noExternalDeps
4749
}
4850

4951
/** Return a common starting point for all Vite actions */
5052
export async function createVite(
5153
commandConfig: ViteConfigWithSSR,
5254
{ astroConfig, logging, mode }: CreateViteOptions
5355
): Promise<ViteConfigWithSSR> {
54-
// Scan for any third-party Astro packages. Vite needs these to be passed to `ssr.noExternal`.
55-
const astroPackages = await getAstroPackages(astroConfig);
56+
const thirdPartyAstroPackages = await getAstroPackages(astroConfig);
5657
// Start with the Vite configuration that Astro core needs
5758
const commonConfig: ViteConfigWithSSR = {
5859
cacheDir: fileURLToPath(new URL('./node_modules/.vite/', astroConfig.root)), // using local caches allows Astro to be used in monorepos, etc.
@@ -82,7 +83,6 @@ export async function createVite(
8283
'import.meta.env.SITE': astroConfig.site ? `'${astroConfig.site}'` : 'undefined',
8384
},
8485
server: {
85-
force: true, // force dependency rebuild (TODO: enabled only while next is unstable; eventually only call in "production" mode?)
8686
hmr:
8787
process.env.NODE_ENV === 'test' || process.env.NODE_ENV === 'production'
8888
? false
@@ -115,11 +115,12 @@ export async function createVite(
115115
],
116116
conditions: ['astro'],
117117
},
118-
// Note: SSR API is in beta (https://vitejs.dev/guide/ssr.html)
119118
ssr: {
120-
external: [...ALWAYS_EXTERNAL],
121-
noExternal: [...ALWAYS_NOEXTERNAL, ...astroPackages],
122-
},
119+
noExternal: [
120+
...getSsrNoExternalDeps(astroConfig.root),
121+
...thirdPartyAstroPackages,
122+
],
123+
}
123124
};
124125

125126
// Merge configs: we merge vite configuration objects together in the following order,
@@ -131,27 +132,33 @@ export async function createVite(
131132
let result = commonConfig;
132133
result = vite.mergeConfig(result, astroConfig.vite || {});
133134
result = vite.mergeConfig(result, commandConfig);
134-
sortPlugins(result);
135+
if (result.plugins) {
136+
sortPlugins(result.plugins);
137+
}
135138

136139
return result;
137140
}
138141

139-
function getPluginName(plugin: vite.PluginOption) {
140-
if (plugin && typeof plugin === 'object' && !Array.isArray(plugin)) {
141-
return plugin.name;
142-
}
142+
function isVitePlugin(plugin: vite.PluginOption): plugin is vite.Plugin {
143+
return Boolean(plugin?.hasOwnProperty('name'));
144+
}
145+
146+
function findPluginIndexByName(pluginOptions: vite.PluginOption[], name: string): number {
147+
return pluginOptions.findIndex(function (pluginOption) {
148+
// Use isVitePlugin to ignore nulls, booleans, promises, and arrays
149+
// CAUTION: could be a problem if a plugin we're searching for becomes async!
150+
return isVitePlugin(pluginOption) && pluginOption.name === name
151+
})
143152
}
144153

145-
function sortPlugins(result: ViteConfigWithSSR) {
154+
function sortPlugins(pluginOptions: vite.PluginOption[]) {
146155
// HACK: move mdxPlugin to top because it needs to run before internal JSX plugin
147-
const mdxPluginIndex =
148-
result.plugins?.findIndex((plugin) => getPluginName(plugin) === '@mdx-js/rollup') ?? -1;
156+
const mdxPluginIndex = findPluginIndexByName(pluginOptions, '@mdx-js/rollup');
149157
if (mdxPluginIndex === -1) return;
150-
const jsxPluginIndex =
151-
result.plugins?.findIndex((plugin) => getPluginName(plugin) === 'astro:jsx') ?? -1;
152-
const mdxPlugin = result.plugins?.[mdxPluginIndex];
153-
result.plugins?.splice(mdxPluginIndex, 1);
154-
result.plugins?.splice(jsxPluginIndex, 0, mdxPlugin);
158+
const jsxPluginIndex = findPluginIndexByName(pluginOptions, 'astro:jsx');
159+
const mdxPlugin = pluginOptions[mdxPluginIndex];
160+
pluginOptions.splice(mdxPluginIndex, 1);
161+
pluginOptions.splice(jsxPluginIndex, 0, mdxPlugin);
155162
}
156163

157164
// Scans `projectRoot` for third-party Astro packages that could export an `.astro` file

packages/astro/src/core/util.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ export function codeFrame(src: string, loc: ErrorPayload['err']['loc']): string
105105
return output;
106106
}
107107

108-
export function resolveDependency(dep: string, astroConfig: AstroConfig) {
108+
export function resolveDependency(dep: string, projectRoot: URL) {
109109
const resolved = resolve.sync(dep, {
110-
basedir: fileURLToPath(astroConfig.root),
110+
basedir: fileURLToPath(projectRoot),
111111
});
112112
// For Windows compat, we need a fully resolved `file://` URL string
113113
return pathToFileURL(resolved).toString();

packages/astro/src/vite-plugin-astro/hmr.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export async function trackCSSDependencies(
4141
}
4242

4343
// Update the module graph, telling it about our CSS deps.
44-
moduleGraph.updateModuleInfo(mod, depModules, new Set(), true);
44+
moduleGraph.updateModuleInfo(mod, depModules, new Map(), new Set(), new Set(), true);
4545
for (const dep of cssDeps) {
4646
this.addWatchFile(dep);
4747
}

packages/astro/src/vite-plugin-astro/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu
6767
configureServer(server) {
6868
viteDevServer = server;
6969
},
70-
// note: don’t claim .astro files with resolveId() — it prevents Vite from transpiling the final JS (import.meta.globEager, etc.)
70+
// note: don’t claim .astro files with resolveId() — it prevents Vite from transpiling the final JS (import.meta.glob, etc.)
7171
async resolveId(id, from, opts) {
7272
// If resolving from an astro subresource such as a hoisted script,
7373
// we need to resolve relative paths ourselves.

0 commit comments

Comments
 (0)