Use new compiler resolvePath
option (#5133)
This commit is contained in:
parent
643535dcd4
commit
1c477dd8d9
20 changed files with 57 additions and 311 deletions
5
.changeset/dry-dragons-greet.md
Normal file
5
.changeset/dry-dragons-greet.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix `.css?raw` usage
|
5
.changeset/gentle-insects-run.md
Normal file
5
.changeset/gentle-insects-run.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Update `@astrojs/compiler` and use the new `resolvePath` option. This allows removing much of the runtime code, which should improve rendering performance for Astro and MDX pages.
|
|
@ -2,3 +2,4 @@
|
||||||
import Fake from '../abc.astro';
|
import Fake from '../abc.astro';
|
||||||
---
|
---
|
||||||
<h1>Testing unresolved frontmatter import</h1>
|
<h1>Testing unresolved frontmatter import</h1>
|
||||||
|
<Fake />
|
||||||
|
|
|
@ -98,7 +98,7 @@
|
||||||
"test:e2e:match": "playwright test -g"
|
"test:e2e:match": "playwright test -g"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/compiler": "^0.27.1",
|
"@astrojs/compiler": "^0.28.0",
|
||||||
"@astrojs/language-server": "^0.26.2",
|
"@astrojs/language-server": "^0.26.2",
|
||||||
"@astrojs/markdown-remark": "^1.1.3",
|
"@astrojs/markdown-remark": "^1.1.3",
|
||||||
"@astrojs/telemetry": "^1.0.1",
|
"@astrojs/telemetry": "^1.0.1",
|
||||||
|
|
|
@ -16,7 +16,7 @@ import type { SerializedSSRManifest } from '../core/app/types';
|
||||||
import type { PageBuildData } from '../core/build/types';
|
import type { PageBuildData } from '../core/build/types';
|
||||||
import type { AstroConfigSchema } from '../core/config';
|
import type { AstroConfigSchema } from '../core/config';
|
||||||
import type { AstroCookies } from '../core/cookies';
|
import type { AstroCookies } from '../core/cookies';
|
||||||
import type { AstroComponentFactory, Metadata } from '../runtime/server';
|
import type { AstroComponentFactory } from '../runtime/server';
|
||||||
export type {
|
export type {
|
||||||
MarkdownHeading,
|
MarkdownHeading,
|
||||||
MarkdownMetadata,
|
MarkdownMetadata,
|
||||||
|
@ -968,7 +968,6 @@ export type AsyncRendererComponentFn<U> = (
|
||||||
|
|
||||||
/** Generic interface for a component (Astro, Svelte, React, etc.) */
|
/** Generic interface for a component (Astro, Svelte, React, etc.) */
|
||||||
export interface ComponentInstance {
|
export interface ComponentInstance {
|
||||||
$$metadata: Metadata;
|
|
||||||
default: AstroComponentFactory;
|
default: AstroComponentFactory;
|
||||||
css?: string[];
|
css?: string[];
|
||||||
getStaticPaths?: (options: GetStaticPathsOptions) => GetStaticPathsResult;
|
getStaticPaths?: (options: GetStaticPathsOptions) => GetStaticPathsResult;
|
||||||
|
|
|
@ -223,38 +223,6 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[]
|
||||||
});
|
});
|
||||||
output.source = minifiedCSS;
|
output.source = minifiedCSS;
|
||||||
}
|
}
|
||||||
} else if (output.type === 'chunk') {
|
|
||||||
// vite:css-post removes "pure CSS" JavaScript chunks, that is chunks that only contain a comment
|
|
||||||
// about it being a CSS module. We need to keep these chunks around because Astro
|
|
||||||
// re-imports all modules as their namespace `import * as module1 from 'some/path';
|
|
||||||
// in order to determine if one of them is a side-effectual web component.
|
|
||||||
// If we ever get rid of that feature, the code below can be removed.
|
|
||||||
for (const [imp, bindings] of Object.entries(output.importedBindings)) {
|
|
||||||
if (imp.startsWith('chunks/') && !bundle[imp] && output.code.includes(imp)) {
|
|
||||||
// This just creates an empty chunk module so that the main entry module
|
|
||||||
// that is importing it doesn't break.
|
|
||||||
const depChunk: OutputChunk = {
|
|
||||||
type: 'chunk',
|
|
||||||
fileName: imp,
|
|
||||||
name: imp,
|
|
||||||
facadeModuleId: imp,
|
|
||||||
code: `/* Pure CSS chunk ${imp} */ ${bindings
|
|
||||||
.map((b) => `export const ${b} = {};`)
|
|
||||||
.join('')}`,
|
|
||||||
dynamicImports: [],
|
|
||||||
implicitlyLoadedBefore: [],
|
|
||||||
importedBindings: {},
|
|
||||||
imports: [],
|
|
||||||
referencedFiles: [],
|
|
||||||
exports: Array.from(bindings),
|
|
||||||
isDynamicEntry: false,
|
|
||||||
isEntry: false,
|
|
||||||
isImplicitEntry: false,
|
|
||||||
modules: {},
|
|
||||||
};
|
|
||||||
bundle[imp] = depChunk;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import type { TransformResult } from '@astrojs/compiler';
|
import type { TransformResult } from '@astrojs/compiler';
|
||||||
import path from 'path';
|
|
||||||
import type { AstroConfig } from '../../@types/astro';
|
import type { AstroConfig } from '../../@types/astro';
|
||||||
import type { TransformStyle } from './types';
|
import type { TransformStyle } from './types';
|
||||||
|
|
||||||
import { transform } from '@astrojs/compiler';
|
import { transform } from '@astrojs/compiler';
|
||||||
import { AstroErrorCodes } from '../errors.js';
|
import { AstroErrorCodes } from '../errors.js';
|
||||||
import { prependForwardSlash, removeLeadingForwardSlashWindows } from '../path.js';
|
import { prependForwardSlash } from '../path.js';
|
||||||
import { AggregateError, resolveJsToTs, viteID } from '../util.js';
|
import { AggregateError, resolvePath, viteID } from '../util.js';
|
||||||
import { createStylePreprocessor } from './style.js';
|
import { createStylePreprocessor } from './style.js';
|
||||||
|
|
||||||
type CompilationCache = Map<string, CompileResult>;
|
type CompilationCache = Map<string, CompileResult>;
|
||||||
|
@ -37,13 +36,7 @@ async function compile({
|
||||||
// use `sourcemap: "both"` so that sourcemap is included in the code
|
// use `sourcemap: "both"` so that sourcemap is included in the code
|
||||||
// result passed to esbuild, but also available in the catch handler.
|
// result passed to esbuild, but also available in the catch handler.
|
||||||
const transformResult = await transform(source, {
|
const transformResult = await transform(source, {
|
||||||
// For Windows compat, prepend filename with `/`.
|
pathname: filename,
|
||||||
// Note this is required because the compiler uses URLs to parse and built paths.
|
|
||||||
// TODO: Ideally the compiler could expose a `resolvePath` function so that we can
|
|
||||||
// unify how we handle path in a bundler-agnostic way.
|
|
||||||
// At the meantime workaround with a slash and remove them in `astro:postprocess`
|
|
||||||
// when they are used in `client:component-path`.
|
|
||||||
pathname: prependForwardSlash(filename),
|
|
||||||
projectRoot: config.root.toString(),
|
projectRoot: config.root.toString(),
|
||||||
site: config.site?.toString(),
|
site: config.site?.toString(),
|
||||||
sourcefile: filename,
|
sourcefile: filename,
|
||||||
|
@ -54,6 +47,9 @@ async function compile({
|
||||||
// TODO: baseline flag
|
// TODO: baseline flag
|
||||||
experimentalStaticExtraction: true,
|
experimentalStaticExtraction: true,
|
||||||
preprocessStyle: createStylePreprocessor(transformStyle, cssDeps, cssTransformErrors),
|
preprocessStyle: createStylePreprocessor(transformStyle, cssDeps, cssTransformErrors),
|
||||||
|
async resolvePath(specifier) {
|
||||||
|
return resolvePath(specifier, filename);
|
||||||
|
},
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
// throw compiler errors here if encountered
|
// throw compiler errors here if encountered
|
||||||
|
@ -88,32 +84,6 @@ async function compile({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Also fix path before returning. Example original resolvedPaths:
|
|
||||||
// - @astrojs/preact/client.js
|
|
||||||
// - @/components/Foo.vue
|
|
||||||
// - /Users/macos/project/src/Foo.vue
|
|
||||||
// - /C:/Windows/project/src/Foo.vue
|
|
||||||
for (const c of compileResult.clientOnlyComponents) {
|
|
||||||
c.resolvedPath = removeLeadingForwardSlashWindows(c.resolvedPath);
|
|
||||||
// The compiler trims .jsx by default, prevent this
|
|
||||||
if (c.specifier.endsWith('.jsx') && !c.resolvedPath.endsWith('.jsx')) {
|
|
||||||
c.resolvedPath += '.jsx';
|
|
||||||
}
|
|
||||||
if (path.isAbsolute(c.resolvedPath)) {
|
|
||||||
c.resolvedPath = resolveJsToTs(c.resolvedPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const c of compileResult.hydratedComponents) {
|
|
||||||
c.resolvedPath = removeLeadingForwardSlashWindows(c.resolvedPath);
|
|
||||||
// The compiler trims .jsx by default, prevent this
|
|
||||||
if (c.specifier.endsWith('.jsx') && !c.resolvedPath.endsWith('.jsx')) {
|
|
||||||
c.resolvedPath += '.jsx';
|
|
||||||
}
|
|
||||||
if (path.isAbsolute(c.resolvedPath)) {
|
|
||||||
c.resolvedPath = resolveJsToTs(c.resolvedPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return compileResult;
|
return compileResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ import { isPage, resolveIdToUrl } from '../../util.js';
|
||||||
import { createRenderContext, renderPage as coreRenderPage } from '../index.js';
|
import { createRenderContext, renderPage as coreRenderPage } from '../index.js';
|
||||||
import { filterFoundRenderers, loadRenderer } from '../renderer.js';
|
import { filterFoundRenderers, loadRenderer } from '../renderer.js';
|
||||||
import { RouteCache } from '../route-cache.js';
|
import { RouteCache } from '../route-cache.js';
|
||||||
import { collectMdMetadata } from '../util.js';
|
|
||||||
import { getStylesForURL } from './css.js';
|
import { getStylesForURL } from './css.js';
|
||||||
import type { DevelopmentEnvironment } from './environment';
|
import type { DevelopmentEnvironment } from './environment';
|
||||||
import { getScriptsForURL } from './scripts.js';
|
import { getScriptsForURL } from './scripts.js';
|
||||||
|
@ -94,16 +93,6 @@ export async function preload({
|
||||||
const renderers = await loadRenderers(env.viteServer, env.settings);
|
const renderers = await loadRenderers(env.viteServer, env.settings);
|
||||||
// Load the module from the Vite SSR Runtime.
|
// Load the module from the Vite SSR Runtime.
|
||||||
const mod = (await env.viteServer.ssrLoadModule(fileURLToPath(filePath))) as ComponentInstance;
|
const mod = (await env.viteServer.ssrLoadModule(fileURLToPath(filePath))) as ComponentInstance;
|
||||||
if (env.viteServer.config.mode === 'development' || !mod?.$$metadata) {
|
|
||||||
return [renderers, mod];
|
|
||||||
}
|
|
||||||
|
|
||||||
// append all nested markdown metadata to mod.$$metadata
|
|
||||||
const modGraph = await env.viteServer.moduleGraph.getModuleByUrl(fileURLToPath(filePath));
|
|
||||||
if (modGraph) {
|
|
||||||
await collectMdMetadata(mod.$$metadata, modGraph, env.viteServer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [renderers, mod];
|
return [renderers, mod];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,3 @@
|
||||||
import type { ModuleNode, ViteDevServer } from 'vite';
|
|
||||||
import type { Metadata } from '../../runtime/server/metadata.js';
|
|
||||||
|
|
||||||
/** Check if a URL is already valid */
|
|
||||||
export function isValidURL(url: string): boolean {
|
|
||||||
try {
|
|
||||||
new URL(url);
|
|
||||||
return true;
|
|
||||||
} catch (e) {}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://vitejs.dev/guide/features.html#css-pre-processors
|
// https://vitejs.dev/guide/features.html#css-pre-processors
|
||||||
export const STYLE_EXTENSIONS = new Set([
|
export const STYLE_EXTENSIONS = new Set([
|
||||||
'.css',
|
'.css',
|
||||||
|
@ -22,59 +10,9 @@ export const STYLE_EXTENSIONS = new Set([
|
||||||
'.less',
|
'.less',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// duplicate const from vite-plugin-markdown
|
|
||||||
// can't import directly due to Deno bundling issue
|
|
||||||
// (node fs import failing during prod builds)
|
|
||||||
const MARKDOWN_IMPORT_FLAG = '?mdImport';
|
|
||||||
|
|
||||||
const cssRe = new RegExp(
|
const cssRe = new RegExp(
|
||||||
`\\.(${Array.from(STYLE_EXTENSIONS)
|
`\\.(${Array.from(STYLE_EXTENSIONS)
|
||||||
.map((s) => s.slice(1))
|
.map((s) => s.slice(1))
|
||||||
.join('|')})($|\\?)`
|
.join('|')})($|\\?)`
|
||||||
);
|
);
|
||||||
export const isCSSRequest = (request: string): boolean => cssRe.test(request);
|
export const isCSSRequest = (request: string): boolean => cssRe.test(request);
|
||||||
|
|
||||||
// During prod builds, some modules have dependencies we should preload by hand
|
|
||||||
// Ex. markdown files imported asynchronously or via Astro.glob(...)
|
|
||||||
// This calls each md file's $$loadMetadata to discover those dependencies
|
|
||||||
// and writes all results to the input `metadata` object
|
|
||||||
const seenMdMetadata = new Set<string>();
|
|
||||||
export async function collectMdMetadata(
|
|
||||||
metadata: Metadata,
|
|
||||||
modGraph: ModuleNode,
|
|
||||||
viteServer: ViteDevServer
|
|
||||||
) {
|
|
||||||
const importedModules = [...(modGraph?.importedModules ?? [])];
|
|
||||||
await Promise.all(
|
|
||||||
importedModules.map(async (importedModule) => {
|
|
||||||
// recursively check for importedModules
|
|
||||||
if (!importedModule.id || seenMdMetadata.has(importedModule.id)) return;
|
|
||||||
|
|
||||||
seenMdMetadata.add(importedModule.id);
|
|
||||||
await collectMdMetadata(metadata, importedModule, viteServer);
|
|
||||||
|
|
||||||
if (!importedModule?.id?.endsWith(MARKDOWN_IMPORT_FLAG)) return;
|
|
||||||
|
|
||||||
const mdSSRMod = await viteServer.ssrLoadModule(importedModule.id);
|
|
||||||
const mdMetadata = (await mdSSRMod.$$loadMetadata?.()) as Metadata;
|
|
||||||
if (!mdMetadata) return;
|
|
||||||
|
|
||||||
for (let mdMod of mdMetadata.modules) {
|
|
||||||
mdMod.specifier = mdMetadata.resolvePath(mdMod.specifier);
|
|
||||||
metadata.modules.push(mdMod);
|
|
||||||
}
|
|
||||||
for (let mdHoisted of mdMetadata.hoisted) {
|
|
||||||
metadata.hoisted.push(mdHoisted);
|
|
||||||
}
|
|
||||||
for (let mdHydrated of mdMetadata.hydratedComponents) {
|
|
||||||
metadata.hydratedComponents.push(mdHydrated);
|
|
||||||
}
|
|
||||||
for (let mdClientOnly of mdMetadata.clientOnlyComponents) {
|
|
||||||
metadata.clientOnlyComponents.push(mdClientOnly);
|
|
||||||
}
|
|
||||||
for (let mdHydrationDirective of mdMetadata.hydrationDirectives) {
|
|
||||||
metadata.hydrationDirectives.add(mdHydrationDirective);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import path from 'path';
|
||||||
import resolve from 'resolve';
|
import resolve from 'resolve';
|
||||||
import slash from 'slash';
|
import slash from 'slash';
|
||||||
import { fileURLToPath, pathToFileURL } from 'url';
|
import { fileURLToPath, pathToFileURL } from 'url';
|
||||||
import type { ErrorPayload, ViteDevServer } from 'vite';
|
import { ErrorPayload, normalizePath, ViteDevServer } from 'vite';
|
||||||
import type { AstroConfig, AstroSettings, RouteType } from '../@types/astro';
|
import type { AstroConfig, AstroSettings, RouteType } from '../@types/astro';
|
||||||
import { prependForwardSlash, removeTrailingForwardSlash } from './path.js';
|
import { prependForwardSlash, removeTrailingForwardSlash } from './path.js';
|
||||||
|
|
||||||
|
@ -227,6 +227,18 @@ export function resolveJsToTs(filePath: string) {
|
||||||
return filePath;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const AggregateError =
|
export const AggregateError =
|
||||||
typeof (globalThis as any).AggregateError !== 'undefined'
|
typeof (globalThis as any).AggregateError !== 'undefined'
|
||||||
? (globalThis as any).AggregateError
|
? (globalThis as any).AggregateError
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import type { PluginObj } from '@babel/core';
|
import type { PluginObj } from '@babel/core';
|
||||||
import * as t from '@babel/types';
|
import * as t from '@babel/types';
|
||||||
import npath from 'path';
|
import { resolvePath } from '../core/util.js';
|
||||||
import { normalizePath } from 'vite';
|
|
||||||
import { resolveJsToTs } from '../core/util.js';
|
|
||||||
import { HydrationDirectiveProps } from '../runtime/server/hydration.js';
|
import { HydrationDirectiveProps } from '../runtime/server/hydration.js';
|
||||||
import type { PluginMetadata } from '../vite-plugin-astro/types';
|
import type { PluginMetadata } from '../vite-plugin-astro/types';
|
||||||
|
|
||||||
|
@ -217,13 +215,7 @@ export default function astroJSX(): PluginObj {
|
||||||
|
|
||||||
const meta = path.getData('import');
|
const meta = path.getData('import');
|
||||||
if (meta) {
|
if (meta) {
|
||||||
let resolvedPath: string;
|
const resolvedPath = resolvePath(meta.path, state.filename!);
|
||||||
if (meta.path.startsWith('.')) {
|
|
||||||
resolvedPath = normalizePath(npath.resolve(npath.dirname(state.filename!), meta.path));
|
|
||||||
resolvedPath = resolveJsToTs(resolvedPath);
|
|
||||||
} else {
|
|
||||||
resolvedPath = meta.path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isClientOnly) {
|
if (isClientOnly) {
|
||||||
(state.file.metadata as PluginMetadata).astro.clientOnlyComponents.push({
|
(state.file.metadata as PluginMetadata).astro.clientOnlyComponents.push({
|
||||||
|
@ -297,13 +289,7 @@ export default function astroJSX(): PluginObj {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let resolvedPath: string;
|
const resolvedPath = resolvePath(meta.path, state.filename!);
|
||||||
if (meta.path.startsWith('.')) {
|
|
||||||
resolvedPath = normalizePath(npath.resolve(npath.dirname(state.filename!), meta.path));
|
|
||||||
resolvedPath = resolveJsToTs(resolvedPath);
|
|
||||||
} else {
|
|
||||||
resolvedPath = meta.path;
|
|
||||||
}
|
|
||||||
if (isClientOnly) {
|
if (isClientOnly) {
|
||||||
(state.file.metadata as PluginMetadata).astro.clientOnlyComponents.push({
|
(state.file.metadata as PluginMetadata).astro.clientOnlyComponents.push({
|
||||||
exportName: meta.name,
|
exportName: meta.name,
|
||||||
|
|
|
@ -2,8 +2,6 @@ export { createAstro } from './astro-global.js';
|
||||||
export { renderEndpoint } from './endpoint.js';
|
export { renderEndpoint } from './endpoint.js';
|
||||||
export { escapeHTML, HTMLBytes, HTMLString, markHTMLString, unescapeHTML } from './escape.js';
|
export { escapeHTML, HTMLBytes, HTMLString, markHTMLString, unescapeHTML } from './escape.js';
|
||||||
export { renderJSX } from './jsx.js';
|
export { renderJSX } from './jsx.js';
|
||||||
export type { Metadata } from './metadata';
|
|
||||||
export { createMetadata } from './metadata.js';
|
|
||||||
export {
|
export {
|
||||||
addAttribute,
|
addAttribute,
|
||||||
defineScriptVars,
|
defineScriptVars,
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
import { removeLeadingForwardSlashWindows } from '../../core/path.js';
|
|
||||||
|
|
||||||
interface ModuleInfo {
|
|
||||||
module: Record<string, any>;
|
|
||||||
specifier: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ComponentMetadata {
|
|
||||||
componentExport: string;
|
|
||||||
componentUrl: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CreateMetadataOptions {
|
|
||||||
modules: ModuleInfo[];
|
|
||||||
hydratedComponents: any[];
|
|
||||||
clientOnlyComponents: any[];
|
|
||||||
hydrationDirectives: Set<string>;
|
|
||||||
hoisted: any[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Metadata {
|
|
||||||
public filePath: string;
|
|
||||||
public modules: ModuleInfo[];
|
|
||||||
public hoisted: any[];
|
|
||||||
public hydratedComponents: any[];
|
|
||||||
public clientOnlyComponents: any[];
|
|
||||||
public hydrationDirectives: Set<string>;
|
|
||||||
|
|
||||||
private mockURL: URL;
|
|
||||||
private metadataCache: Map<any, ComponentMetadata | null>;
|
|
||||||
|
|
||||||
constructor(filePathname: string, opts: CreateMetadataOptions) {
|
|
||||||
this.modules = opts.modules;
|
|
||||||
this.hoisted = opts.hoisted;
|
|
||||||
this.hydratedComponents = opts.hydratedComponents;
|
|
||||||
this.clientOnlyComponents = opts.clientOnlyComponents;
|
|
||||||
this.hydrationDirectives = opts.hydrationDirectives;
|
|
||||||
this.filePath = removeLeadingForwardSlashWindows(filePathname);
|
|
||||||
this.mockURL = new URL(filePathname, 'http://example.com');
|
|
||||||
this.metadataCache = new Map<any, ComponentMetadata | null>();
|
|
||||||
}
|
|
||||||
|
|
||||||
resolvePath(specifier: string): string {
|
|
||||||
if (specifier.startsWith('.')) {
|
|
||||||
// NOTE: ideally we should use `path.resolve` here, but this is part
|
|
||||||
// of server output code, which needs to work on platform that doesn't
|
|
||||||
// have the `path` module. Use `URL` here since we deal with posix only.
|
|
||||||
const url = new URL(specifier, this.mockURL);
|
|
||||||
return removeLeadingForwardSlashWindows(decodeURI(url.pathname));
|
|
||||||
} else {
|
|
||||||
return specifier;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getPath(Component: any): string | null {
|
|
||||||
const metadata = this.getComponentMetadata(Component);
|
|
||||||
return metadata?.componentUrl || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
getExport(Component: any): string | null {
|
|
||||||
const metadata = this.getComponentMetadata(Component);
|
|
||||||
return metadata?.componentExport || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getComponentMetadata(Component: any): ComponentMetadata | null {
|
|
||||||
if (this.metadataCache.has(Component)) {
|
|
||||||
return this.metadataCache.get(Component)!;
|
|
||||||
}
|
|
||||||
const metadata = this.findComponentMetadata(Component);
|
|
||||||
this.metadataCache.set(Component, metadata);
|
|
||||||
return metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
private findComponentMetadata(Component: any): ComponentMetadata | null {
|
|
||||||
const isCustomElement = typeof Component === 'string';
|
|
||||||
for (const { module, specifier } of this.modules) {
|
|
||||||
const id = this.resolvePath(specifier);
|
|
||||||
for (const [key, value] of Object.entries(module)) {
|
|
||||||
if (isCustomElement) {
|
|
||||||
if (key === 'tagName' && Component === value) {
|
|
||||||
return {
|
|
||||||
componentExport: key,
|
|
||||||
componentUrl: id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else if (Component === value) {
|
|
||||||
return {
|
|
||||||
componentExport: key,
|
|
||||||
componentUrl: id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createMetadata(filePathname: string, options: CreateMetadataOptions) {
|
|
||||||
return new Metadata(filePathname, options);
|
|
||||||
}
|
|
|
@ -1,28 +1,17 @@
|
||||||
import { parse as babelParser } from '@babel/parser';
|
import { parse as babelParser } from '@babel/parser';
|
||||||
import type {
|
import type { ArrowFunctionExpressionKind, CallExpressionKind } from 'ast-types/gen/kinds';
|
||||||
ArrowFunctionExpressionKind,
|
|
||||||
CallExpressionKind,
|
|
||||||
StringLiteralKind,
|
|
||||||
} from 'ast-types/gen/kinds';
|
|
||||||
import type { NodePath } from 'ast-types/lib/node-path';
|
import type { NodePath } from 'ast-types/lib/node-path';
|
||||||
import npath from 'path';
|
|
||||||
import { parse, print, types, visit } from 'recast';
|
import { parse, print, types, visit } from 'recast';
|
||||||
import type { Plugin } from 'vite';
|
import type { Plugin } from 'vite';
|
||||||
import type { AstroSettings } from '../@types/astro';
|
import type { AstroSettings } from '../@types/astro';
|
||||||
import { removeLeadingForwardSlashWindows } from '../core/path.js';
|
|
||||||
import { resolveJsToTs } from '../core/util.js';
|
|
||||||
|
|
||||||
// Check for `Astro.glob()`. Be very forgiving of whitespace. False positives are okay.
|
// Check for `Astro.glob()`. Be very forgiving of whitespace. False positives are okay.
|
||||||
const ASTRO_GLOB_REGEX = /Astro2?\s*\.\s*glob\s*\(/;
|
const ASTRO_GLOB_REGEX = /Astro2?\s*\.\s*glob\s*\(/;
|
||||||
const CLIENT_COMPONENT_PATH_REGEX = /['"]client:component-path['"]:/;
|
|
||||||
|
|
||||||
interface AstroPluginOptions {
|
interface AstroPluginOptions {
|
||||||
settings: AstroSettings;
|
settings: AstroSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
// esbuild transforms the component-scoped Astro into Astro2, so need to check both.
|
|
||||||
const validAstroGlobalNames = new Set(['Astro', 'Astro2']);
|
|
||||||
|
|
||||||
export default function astro(_opts: AstroPluginOptions): Plugin {
|
export default function astro(_opts: AstroPluginOptions): Plugin {
|
||||||
return {
|
return {
|
||||||
name: 'astro:postprocess',
|
name: 'astro:postprocess',
|
||||||
|
@ -34,7 +23,7 @@ export default function astro(_opts: AstroPluginOptions): Plugin {
|
||||||
|
|
||||||
// Optimization: Detect usage with a quick string match.
|
// Optimization: Detect usage with a quick string match.
|
||||||
// Only perform the transform if this function is found
|
// Only perform the transform if this function is found
|
||||||
if (!ASTRO_GLOB_REGEX.test(code) && !CLIENT_COMPONENT_PATH_REGEX.test(code)) {
|
if (!ASTRO_GLOB_REGEX.test(code)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,33 +74,6 @@ export default function astro(_opts: AstroPluginOptions): Plugin {
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
visitObjectProperty: function (path) {
|
|
||||||
// Filter out none 'client:component-path' properties
|
|
||||||
if (
|
|
||||||
!types.namedTypes.StringLiteral.check(path.node.key) ||
|
|
||||||
path.node.key.value !== 'client:component-path' ||
|
|
||||||
!types.namedTypes.StringLiteral.check(path.node.value)
|
|
||||||
) {
|
|
||||||
this.traverse(path);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Patch up client:component-path value that has leading slash on Windows.
|
|
||||||
// See `compile.ts` for more details, this will be fixed in the Astro compiler.
|
|
||||||
const valuePath = path.get('value') as NodePath;
|
|
||||||
let value = valuePath.value.value;
|
|
||||||
value = removeLeadingForwardSlashWindows(value);
|
|
||||||
// Add back `.jsx` stripped by the compiler by loosely checking the code
|
|
||||||
if (code.includes(npath.basename(value) + '.jsx')) {
|
|
||||||
value += '.jsx';
|
|
||||||
}
|
|
||||||
value = resolveJsToTs(value);
|
|
||||||
valuePath.replace({
|
|
||||||
type: 'StringLiteral',
|
|
||||||
value,
|
|
||||||
} as StringLiteralKind);
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = print(ast);
|
const result = print(ast);
|
||||||
|
|
|
@ -120,9 +120,6 @@ export default function markdown({ settings }: AstroPluginOptions): Plugin {
|
||||||
export async function compiledContent() {
|
export async function compiledContent() {
|
||||||
return load().then((m) => m.compiledContent());
|
return load().then((m) => m.compiledContent());
|
||||||
}
|
}
|
||||||
export function $$loadMetadata() {
|
|
||||||
return load().then((m) => m.$$metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deferred
|
// Deferred
|
||||||
export default async function load() {
|
export default async function load() {
|
||||||
|
|
|
@ -266,6 +266,13 @@ describe('CSS', function () {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Vite features', () => {
|
||||||
|
it('.css?raw return a string', () => {
|
||||||
|
const el = $('#css-raw');
|
||||||
|
expect(el.text()).to.equal('.foo {color: red;}');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// with "build" handling CSS checking, the dev tests are mostly testing the paths resolve in dev
|
// with "build" handling CSS checking, the dev tests are mostly testing the paths resolve in dev
|
||||||
|
@ -375,5 +382,10 @@ describe('CSS', function () {
|
||||||
'Should not have found a preload for the dynamic CSS'
|
'Should not have found a preload for the dynamic CSS'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('.css?raw return a string', () => {
|
||||||
|
const el = $('#css-raw');
|
||||||
|
expect(el.text()).to.equal('.foo {color: red;}');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -23,6 +23,7 @@ import SvelteDynamic from '../components/SvelteDynamic.svelte';
|
||||||
import '../styles/imported-url.css';
|
import '../styles/imported-url.css';
|
||||||
import '../styles/imported.sass';
|
import '../styles/imported.sass';
|
||||||
import '../styles/imported.scss';
|
import '../styles/imported.scss';
|
||||||
|
import raw from '../styles/raw.css?raw'
|
||||||
---
|
---
|
||||||
|
|
||||||
<html>
|
<html>
|
||||||
|
@ -71,6 +72,7 @@ import '../styles/imported.scss';
|
||||||
<VueScss />
|
<VueScss />
|
||||||
<ReactDynamic client:load />
|
<ReactDynamic client:load />
|
||||||
<SvelteDynamic client:load />
|
<SvelteDynamic client:load />
|
||||||
|
<pre id="css-raw">{raw}</pre>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
1
packages/astro/test/fixtures/0-css/src/styles/raw.css
vendored
Normal file
1
packages/astro/test/fixtures/0-css/src/styles/raw.css
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.foo {color: red;}
|
|
@ -12,5 +12,6 @@ import something from '../something.js';
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Astro</h1>
|
<h1>Astro</h1>
|
||||||
|
<p>{something}</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
|
@ -362,7 +362,7 @@ importers:
|
||||||
|
|
||||||
packages/astro:
|
packages/astro:
|
||||||
specifiers:
|
specifiers:
|
||||||
'@astrojs/compiler': ^0.27.1
|
'@astrojs/compiler': ^0.28.0
|
||||||
'@astrojs/language-server': ^0.26.2
|
'@astrojs/language-server': ^0.26.2
|
||||||
'@astrojs/markdown-remark': ^1.1.3
|
'@astrojs/markdown-remark': ^1.1.3
|
||||||
'@astrojs/telemetry': ^1.0.1
|
'@astrojs/telemetry': ^1.0.1
|
||||||
|
@ -458,7 +458,7 @@ importers:
|
||||||
yargs-parser: ^21.0.1
|
yargs-parser: ^21.0.1
|
||||||
zod: ^3.17.3
|
zod: ^3.17.3
|
||||||
dependencies:
|
dependencies:
|
||||||
'@astrojs/compiler': 0.27.2
|
'@astrojs/compiler': 0.28.0
|
||||||
'@astrojs/language-server': 0.26.2
|
'@astrojs/language-server': 0.26.2
|
||||||
'@astrojs/markdown-remark': link:../markdown/remark
|
'@astrojs/markdown-remark': link:../markdown/remark
|
||||||
'@astrojs/telemetry': link:../telemetry
|
'@astrojs/telemetry': link:../telemetry
|
||||||
|
@ -3793,8 +3793,8 @@ packages:
|
||||||
resolution: {integrity: sha512-vBMPy9ok4iLapSyCCT1qsZ9dK7LkVFl9mObtLEmWiec9myGHS9h2kQY2xzPeFNJiWXUf9O6tSyQpQTy5As/p3g==}
|
resolution: {integrity: sha512-vBMPy9ok4iLapSyCCT1qsZ9dK7LkVFl9mObtLEmWiec9myGHS9h2kQY2xzPeFNJiWXUf9O6tSyQpQTy5As/p3g==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@astrojs/compiler/0.27.2:
|
/@astrojs/compiler/0.28.0:
|
||||||
resolution: {integrity: sha512-VG4X87cUkcmT40HqEwShQzUgl0VSnVTszobbmnhAOkHzdoWMxhwAm61A2o5fEsv6eEK8M0lW/fGwkSofYM5GcQ==}
|
resolution: {integrity: sha512-Ju8GAbupzSG5/binq+4Em7sb1yoaWhirIe0cdzeb+BDOfPssu6BWZxY+qytZC6zV+lQlZpujcanMsnexyj1C3A==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@astrojs/language-server/0.26.2:
|
/@astrojs/language-server/0.26.2:
|
||||||
|
|
Loading…
Add table
Reference in a new issue