mirror of
https://github.com/withastro/astro.git
synced 2025-04-07 23:41:43 -05:00
fix(container): breakdown files to avoid importing vite
(#11327)
* fix(container): breakdown files to avoid importing `vite` * chore: update imports inside tests * restore code * format
This commit is contained in:
parent
d9e6190a0d
commit
0df81422a8
18 changed files with 126 additions and 120 deletions
.changeset
packages/astro
src
container
content
core
jsx
vite-plugin-astro-server
vite-plugin-scanner
test/units
5
.changeset/happy-boxes-collect.md
Normal file
5
.changeset/happy-boxes-collect.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Fixes an issue with the container APIs where a runtime error was thrown during the build, when using `pnpm` as package manager.
|
|
@ -14,8 +14,8 @@ import type {
|
|||
SSRManifest,
|
||||
SSRResult,
|
||||
} from '../@types/astro.js';
|
||||
import { validateConfig } from '../core/config/config.js';
|
||||
import { ASTRO_CONFIG_DEFAULTS } from '../core/config/schema.js';
|
||||
import { validateConfig } from '../core/config/validate.js';
|
||||
import { Logger } from '../core/logger/core.js';
|
||||
import { nodeLogDestination } from '../core/logger/node.js';
|
||||
import { removeLeadingForwardSlash } from '../core/path.js';
|
||||
|
@ -208,7 +208,7 @@ type AstroContainerConstructor = {
|
|||
renderers?: SSRLoadedRenderer[];
|
||||
manifest?: AstroContainerManifest;
|
||||
resolve?: SSRResult['resolve'];
|
||||
astroConfig: AstroConfig;
|
||||
astroConfig?: AstroConfig;
|
||||
};
|
||||
|
||||
export class experimental_AstroContainer {
|
||||
|
@ -253,10 +253,10 @@ export class experimental_AstroContainer {
|
|||
});
|
||||
}
|
||||
|
||||
async #containerResolve(specifier: string, astroConfig: AstroConfig): Promise<string> {
|
||||
async #containerResolve(specifier: string, astroConfig?: AstroConfig): Promise<string> {
|
||||
const found = this.#pipeline.manifest.entryModules[specifier];
|
||||
if (found) {
|
||||
return new URL(found, astroConfig.build.client).toString();
|
||||
return new URL(found, astroConfig?.build.client).toString();
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
|
|
@ -7,13 +7,10 @@ import type {
|
|||
} from '../@types/astro.js';
|
||||
import { type HeadElements, Pipeline } from '../core/base-pipeline.js';
|
||||
import type { SinglePageBuiltModule } from '../core/build/types.js';
|
||||
import { RouteNotFound } from '../core/errors/errors-data.js';
|
||||
import { AstroError } from '../core/errors/index.js';
|
||||
import {
|
||||
createModuleScriptElement,
|
||||
createStylesheetElementSet,
|
||||
} from '../core/render/ssr-element.js';
|
||||
import { DEFAULT_404_ROUTE } from '../core/routing/astro-designed-error-pages.js';
|
||||
import { findRouteToRewrite } from '../core/routing/rewrite.js';
|
||||
|
||||
export class ContainerPipeline extends Pipeline {
|
||||
|
|
|
@ -3,12 +3,13 @@ import { extname } from 'node:path';
|
|||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import glob from 'fast-glob';
|
||||
import pLimit from 'p-limit';
|
||||
import { type Plugin } from 'vite';
|
||||
import type { Plugin } from 'vite';
|
||||
import type { AstroSettings } from '../@types/astro.js';
|
||||
import { encodeName } from '../core/build/util.js';
|
||||
import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
||||
import { appendForwardSlash, removeFileExtension } from '../core/path.js';
|
||||
import { isServerLikeOutput, rootRelativePath } from '../core/util.js';
|
||||
import { isServerLikeOutput } from '../core/util.js';
|
||||
import { rootRelativePath } from '../core/viteUtils.js';
|
||||
import type { AstroPluginMetadata } from '../vite-plugin-astro/index.js';
|
||||
import {
|
||||
CONTENT_FLAG,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { fileURLToPath } from 'node:url';
|
||||
import glob from 'fast-glob';
|
||||
import type { OutputChunk } from 'rollup';
|
||||
import { type Plugin as VitePlugin } from 'vite';
|
||||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import { getAssetsPrefix } from '../../../assets/utils/getAssetsPrefix.js';
|
||||
import { normalizeTheLocale } from '../../../i18n/index.js';
|
||||
import { toRoutingStrategy } from '../../../i18n/utils.js';
|
||||
|
|
|
@ -9,7 +9,7 @@ import type { AstroPreferences } from '../../preferences/index.js';
|
|||
import type { AstroError } from '../errors/errors.js';
|
||||
import { AggregateError, CompilerError } from '../errors/errors.js';
|
||||
import { AstroErrorData } from '../errors/index.js';
|
||||
import { resolvePath } from '../util.js';
|
||||
import { resolvePath } from '../viteUtils.js';
|
||||
import { type PartialCompileCssResult, createStylePreprocessor } from './style.js';
|
||||
import type { CompileCssResult } from './types.js';
|
||||
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import * as colors from 'kleur/colors';
|
||||
import type { Arguments as Flags } from 'yargs-parser';
|
||||
import { ZodError } from 'zod';
|
||||
import type {
|
||||
AstroConfig,
|
||||
AstroInlineConfig,
|
||||
|
@ -6,49 +11,14 @@ import type {
|
|||
AstroUserConfig,
|
||||
CLIFlags,
|
||||
} from '../../@types/astro.js';
|
||||
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import * as colors from 'kleur/colors';
|
||||
import { ZodError } from 'zod';
|
||||
import { eventConfigError, telemetry } from '../../events/index.js';
|
||||
import { trackAstroConfigZodError } from '../errors/errors.js';
|
||||
import { AstroError, AstroErrorData } from '../errors/index.js';
|
||||
import { formatConfigErrorMessage } from '../messages.js';
|
||||
import { mergeConfig } from './merge.js';
|
||||
import { createRelativeSchema } from './schema.js';
|
||||
import { validateConfig } from './validate.js';
|
||||
import { loadConfigWithVite } from './vite-load.js';
|
||||
|
||||
/** Turn raw config values into normalized values */
|
||||
export async function validateConfig(
|
||||
userConfig: any,
|
||||
root: string,
|
||||
cmd: string
|
||||
): Promise<AstroConfig> {
|
||||
const AstroConfigRelativeSchema = createRelativeSchema(cmd, root);
|
||||
|
||||
// First-Pass Validation
|
||||
let result: AstroConfig;
|
||||
try {
|
||||
result = await AstroConfigRelativeSchema.parseAsync(userConfig);
|
||||
} catch (e) {
|
||||
// Improve config zod error messages
|
||||
if (e instanceof ZodError) {
|
||||
// Mark this error so the callee can decide to suppress Zod's error if needed.
|
||||
// We still want to throw the error to signal an error in validation.
|
||||
trackAstroConfigZodError(e);
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(formatConfigErrorMessage(e) + '\n');
|
||||
telemetry.record(eventConfigError({ cmd, err: e, isFatal: true }));
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
// If successful, return the result as a verified AstroConfig object.
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Convert the generic "yargs" flag object into our own, custom TypeScript object. */
|
||||
// NOTE: This function will be removed in a later PR. Use `flagsToAstroInlineConfig` instead.
|
||||
// All CLI related flow should be located in the `packages/astro/src/cli` directory.
|
||||
|
@ -197,7 +167,22 @@ export async function resolveConfig(
|
|||
|
||||
const userConfig = await loadConfig(root, inlineOnlyConfig.configFile, fsMod);
|
||||
const mergedConfig = mergeConfig(userConfig, inlineUserConfig);
|
||||
const astroConfig = await validateConfig(mergedConfig, root, command);
|
||||
// First-Pass Validation
|
||||
let astroConfig: AstroConfig;
|
||||
try {
|
||||
astroConfig = await validateConfig(mergedConfig, root, command);
|
||||
} catch (e) {
|
||||
// Improve config zod error messages
|
||||
if (e instanceof ZodError) {
|
||||
// Mark this error so the callee can decide to suppress Zod's error if needed.
|
||||
// We still want to throw the error to signal an error in validation.
|
||||
trackAstroConfigZodError(e);
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(formatConfigErrorMessage(e) + '\n');
|
||||
telemetry.record(eventConfigError({ cmd: command, err: e, isFatal: true }));
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
return { userConfig: mergedConfig, astroConfig };
|
||||
}
|
||||
|
|
14
packages/astro/src/core/config/validate.ts
Normal file
14
packages/astro/src/core/config/validate.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import type { AstroConfig } from '../../@types/astro.js';
|
||||
import { createRelativeSchema } from './schema.js';
|
||||
|
||||
/** Turn raw config values into normalized values */
|
||||
export async function validateConfig(
|
||||
userConfig: any,
|
||||
root: string,
|
||||
cmd: string
|
||||
): Promise<AstroConfig> {
|
||||
const AstroConfigRelativeSchema = createRelativeSchema(cmd, root);
|
||||
|
||||
// First-Pass Validation
|
||||
return await AstroConfigRelativeSchema.parseAsync(userConfig);
|
||||
}
|
|
@ -1,11 +1,9 @@
|
|||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { normalizePath } from 'vite';
|
||||
import type { AstroConfig, AstroSettings, RouteType } from '../@types/astro.js';
|
||||
import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './constants.js';
|
||||
import type { ModuleLoader } from './module-loader/index.js';
|
||||
import { prependForwardSlash, removeTrailingForwardSlash, slash } from './path.js';
|
||||
import { removeTrailingForwardSlash, slash } from './path.js';
|
||||
|
||||
/** Returns true if argument is an object of any prototype/class (but not null). */
|
||||
export function isObject(value: unknown): value is Record<string, any> {
|
||||
|
@ -184,54 +182,10 @@ export function relativeToSrcDir(config: AstroConfig, idOrUrl: URL | string) {
|
|||
return id.slice(slash(fileURLToPath(config.srcDir)).length);
|
||||
}
|
||||
|
||||
export function rootRelativePath(
|
||||
root: URL,
|
||||
idOrUrl: URL | string,
|
||||
shouldPrependForwardSlash = true
|
||||
) {
|
||||
let id: string;
|
||||
if (typeof idOrUrl !== 'string') {
|
||||
id = unwrapId(viteID(idOrUrl));
|
||||
} else {
|
||||
id = idOrUrl;
|
||||
}
|
||||
const normalizedRoot = normalizePath(fileURLToPath(root));
|
||||
if (id.startsWith(normalizedRoot)) {
|
||||
id = id.slice(normalizedRoot.length);
|
||||
}
|
||||
return shouldPrependForwardSlash ? prependForwardSlash(id) : id;
|
||||
}
|
||||
|
||||
export function emoji(char: string, fallback: string) {
|
||||
return process.platform !== 'win32' ? char : fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate Vite's resolve and import analysis so we can import the id as an URL
|
||||
* through a script tag or a dynamic import as-is.
|
||||
*/
|
||||
// NOTE: `/@id/` should only be used when the id is fully resolved
|
||||
export async function resolveIdToUrl(loader: ModuleLoader, id: string, root?: URL) {
|
||||
let resultId = await loader.resolveId(id, undefined);
|
||||
// Try resolve jsx to tsx
|
||||
if (!resultId && id.endsWith('.jsx')) {
|
||||
resultId = await loader.resolveId(id.slice(0, -4), undefined);
|
||||
}
|
||||
if (!resultId) {
|
||||
return VALID_ID_PREFIX + id;
|
||||
}
|
||||
if (path.isAbsolute(resultId)) {
|
||||
const normalizedRoot = root && normalizePath(fileURLToPath(root));
|
||||
// Convert to root-relative path if path is inside root
|
||||
if (normalizedRoot && resultId.startsWith(normalizedRoot)) {
|
||||
return resultId.slice(normalizedRoot.length - 1);
|
||||
} else {
|
||||
return '/@fs' + prependForwardSlash(resultId);
|
||||
}
|
||||
}
|
||||
return VALID_ID_PREFIX + resultId;
|
||||
}
|
||||
|
||||
export function resolveJsToTs(filePath: string) {
|
||||
if (filePath.endsWith('.jsx') && !fs.existsSync(filePath)) {
|
||||
const tryPath = filePath.slice(0, -4) + '.tsx';
|
||||
|
@ -242,18 +196,6 @@ export function resolveJsToTs(filePath: string) {
|
|||
return filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the hydration paths so that it can be imported in the client
|
||||
*/
|
||||
export function resolvePath(specifier: string, importer: string) {
|
||||
if (specifier.startsWith('.')) {
|
||||
const absoluteSpecifier = path.resolve(path.dirname(importer), specifier);
|
||||
return resolveJsToTs(normalizePath(absoluteSpecifier));
|
||||
} else {
|
||||
return specifier;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a default NODE_ENV so Vite doesn't set an incorrect default when loading the Astro config
|
||||
*/
|
||||
|
|
62
packages/astro/src/core/viteUtils.ts
Normal file
62
packages/astro/src/core/viteUtils.ts
Normal file
|
@ -0,0 +1,62 @@
|
|||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { normalizePath } from 'vite';
|
||||
import { prependForwardSlash } from '../core/path.js';
|
||||
import type { ModuleLoader } from './module-loader/index.js';
|
||||
import { VALID_ID_PREFIX, resolveJsToTs, unwrapId, viteID } from './util.js';
|
||||
|
||||
/**
|
||||
* Resolve the hydration paths so that it can be imported in the client
|
||||
*/
|
||||
export function resolvePath(specifier: string, importer: string) {
|
||||
if (specifier.startsWith('.')) {
|
||||
const absoluteSpecifier = path.resolve(path.dirname(importer), specifier);
|
||||
return resolveJsToTs(normalizePath(absoluteSpecifier));
|
||||
} else {
|
||||
return specifier;
|
||||
}
|
||||
}
|
||||
|
||||
export function rootRelativePath(
|
||||
root: URL,
|
||||
idOrUrl: URL | string,
|
||||
shouldPrependForwardSlash = true
|
||||
) {
|
||||
let id: string;
|
||||
if (typeof idOrUrl !== 'string') {
|
||||
id = unwrapId(viteID(idOrUrl));
|
||||
} else {
|
||||
id = idOrUrl;
|
||||
}
|
||||
const normalizedRoot = normalizePath(fileURLToPath(root));
|
||||
if (id.startsWith(normalizedRoot)) {
|
||||
id = id.slice(normalizedRoot.length);
|
||||
}
|
||||
return shouldPrependForwardSlash ? prependForwardSlash(id) : id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate Vite's resolve and import analysis so we can import the id as an URL
|
||||
* through a script tag or a dynamic import as-is.
|
||||
*/
|
||||
// NOTE: `/@id/` should only be used when the id is fully resolved
|
||||
export async function resolveIdToUrl(loader: ModuleLoader, id: string, root?: URL) {
|
||||
let resultId = await loader.resolveId(id, undefined);
|
||||
// Try resolve jsx to tsx
|
||||
if (!resultId && id.endsWith('.jsx')) {
|
||||
resultId = await loader.resolveId(id.slice(0, -4), undefined);
|
||||
}
|
||||
if (!resultId) {
|
||||
return VALID_ID_PREFIX + id;
|
||||
}
|
||||
if (path.isAbsolute(resultId)) {
|
||||
const normalizedRoot = root && normalizePath(fileURLToPath(root));
|
||||
// Convert to root-relative path if path is inside root
|
||||
if (normalizedRoot && resultId.startsWith(normalizedRoot)) {
|
||||
return resultId.slice(normalizedRoot.length - 1);
|
||||
} else {
|
||||
return '/@fs' + prependForwardSlash(resultId);
|
||||
}
|
||||
}
|
||||
return VALID_ID_PREFIX + resultId;
|
||||
}
|
|
@ -2,7 +2,7 @@ import type { PluginObj } from '@babel/core';
|
|||
import * as t from '@babel/types';
|
||||
import { AstroError } from '../core/errors/errors.js';
|
||||
import { AstroErrorData } from '../core/errors/index.js';
|
||||
import { resolvePath } from '../core/util.js';
|
||||
import { resolvePath } from '../core/viteUtils.js';
|
||||
import type { PluginMetadata } from '../vite-plugin-astro/types.js';
|
||||
|
||||
const ClientOnlyPlaceholder = 'astro-client-only';
|
||||
|
|
|
@ -9,7 +9,7 @@ import { visit } from 'unist-util-visit';
|
|||
import type { VFile } from 'vfile';
|
||||
import { AstroError } from '../core/errors/errors.js';
|
||||
import { AstroErrorData } from '../core/errors/index.js';
|
||||
import { resolvePath } from '../core/util.js';
|
||||
import { resolvePath } from '../core/viteUtils.js';
|
||||
import type { PluginMetadata } from '../vite-plugin-astro/types.js';
|
||||
|
||||
// This import includes ambient types for hast to include mdx nodes
|
||||
|
|
|
@ -12,18 +12,16 @@ import type {
|
|||
} from '../@types/astro.js';
|
||||
import { getInfoOutput } from '../cli/info/index.js';
|
||||
import { type HeadElements } from '../core/base-pipeline.js';
|
||||
import { shouldAppendForwardSlash } from '../core/build/util.js';
|
||||
import { ASTRO_VERSION, DEFAULT_404_COMPONENT } from '../core/constants.js';
|
||||
import { enhanceViteSSRError } from '../core/errors/dev/index.js';
|
||||
import { RewriteEncounteredAnError } from '../core/errors/errors-data.js';
|
||||
import { AggregateError, AstroError, CSSError, MarkdownError } from '../core/errors/index.js';
|
||||
import { AggregateError, CSSError, MarkdownError } from '../core/errors/index.js';
|
||||
import type { Logger } from '../core/logger/core.js';
|
||||
import type { ModuleLoader } from '../core/module-loader/index.js';
|
||||
import { prependForwardSlash, removeTrailingForwardSlash } from '../core/path.js';
|
||||
import { Pipeline, loadRenderer } from '../core/render/index.js';
|
||||
import { DEFAULT_404_ROUTE, default404Page } from '../core/routing/astro-designed-error-pages.js';
|
||||
import { default404Page } from '../core/routing/astro-designed-error-pages.js';
|
||||
import { findRouteToRewrite } from '../core/routing/rewrite.js';
|
||||
import { isPage, isServerLikeOutput, resolveIdToUrl, viteID } from '../core/util.js';
|
||||
import { isPage, isServerLikeOutput, viteID } from '../core/util.js';
|
||||
import { resolveIdToUrl } from '../core/viteUtils.js';
|
||||
import { PAGE_SCRIPT_ID } from '../vite-plugin-scripts/index.js';
|
||||
import { getStylesForURL } from './css.js';
|
||||
import { getComponentMetadata } from './metadata.js';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { ModuleLoader } from '../core/module-loader/index.js';
|
||||
import { resolveIdToUrl } from '../core/util.js';
|
||||
import { resolveIdToUrl } from '../core/viteUtils.js';
|
||||
|
||||
export function createResolve(loader: ModuleLoader, root: URL) {
|
||||
// Resolves specifiers in the inline hydrated scripts, such as:
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import type { SSRElement } from '../@types/astro.js';
|
||||
import type { ModuleInfo, ModuleLoader } from '../core/module-loader/index.js';
|
||||
import { createModuleScriptElementWithSrc } from '../core/render/ssr-element.js';
|
||||
import { rootRelativePath, viteID } from '../core/util.js';
|
||||
import { viteID } from '../core/util.js';
|
||||
import { rootRelativePath } from '../core/viteUtils.js';
|
||||
import type { PluginMetadata as AstroPluginMetadata } from '../vite-plugin-astro/types.js';
|
||||
import { crawlGraph } from './vite.js';
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@ import type { Plugin as VitePlugin } from 'vite';
|
|||
import { normalizePath } from 'vite';
|
||||
import type { AstroSettings } from '../@types/astro.js';
|
||||
import { type Logger } from '../core/logger/core.js';
|
||||
import { isEndpoint, isPage, isServerLikeOutput, rootRelativePath } from '../core/util.js';
|
||||
import { isEndpoint, isPage, isServerLikeOutput } from '../core/util.js';
|
||||
import { rootRelativePath } from '../core/viteUtils.js';
|
||||
import { getPrerenderDefault } from '../prerender/utils.js';
|
||||
import { scan } from './scan.js';
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as assert from 'node:assert/strict';
|
|||
import { describe, it } from 'node:test';
|
||||
import stripAnsi from 'strip-ansi';
|
||||
import { z } from 'zod';
|
||||
import { validateConfig } from '../../../dist/core/config/config.js';
|
||||
import { validateConfig } from '../../../dist/core/config/validate.js';
|
||||
import { formatConfigErrorMessage } from '../../../dist/core/messages.js';
|
||||
|
||||
describe('Config Validation', () => {
|
||||
|
|
|
@ -3,7 +3,7 @@ import { describe, it } from 'node:test';
|
|||
import { MissingLocale } from '#astro/core/errors/errors-data';
|
||||
import { AstroError } from '#astro/core/errors/index';
|
||||
import { toRoutingStrategy } from '#astro/i18n/utils';
|
||||
import { validateConfig } from '../../../dist/core/config/config.js';
|
||||
import { validateConfig } from '../../../dist/core/config/validate.js';
|
||||
import {
|
||||
getLocaleAbsoluteUrl,
|
||||
getLocaleAbsoluteUrlList,
|
||||
|
|
Loading…
Add table
Reference in a new issue