Skip to content

Commit

Permalink
Refactor Astro plugin and compile flow (#5506)
Browse files Browse the repository at this point in the history
  • Loading branch information
bluwy authored Dec 5, 2022
1 parent a1885ea commit f536a34
Show file tree
Hide file tree
Showing 9 changed files with 335 additions and 266 deletions.
5 changes: 5 additions & 0 deletions .changeset/lazy-walls-sneeze.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Dedupe Astro package when resolving
5 changes: 5 additions & 0 deletions .changeset/seven-seahorses-talk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Refactor Astro compile flow
42 changes: 42 additions & 0 deletions packages/astro/src/core/compile/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { AstroConfig } from '../../@types/astro';
import { compile, CompileProps, CompileResult } from './compile.js';

type CompilationCache = Map<string, CompileResult>;

const configCache = new WeakMap<AstroConfig, CompilationCache>();

export function isCached(config: AstroConfig, filename: string) {
return configCache.has(config) && configCache.get(config)!.has(filename);
}

export function getCachedCompileResult(
config: AstroConfig,
filename: string
): CompileResult | null {
if (!isCached(config, filename)) return null;
return configCache.get(config)!.get(filename)!;
}

export function invalidateCompilation(config: AstroConfig, filename: string) {
if (configCache.has(config)) {
const cache = configCache.get(config)!;
cache.delete(filename);
}
}

export async function cachedCompilation(props: CompileProps): Promise<CompileResult> {
const { astroConfig, filename } = props;
let cache: CompilationCache;
if (!configCache.has(astroConfig)) {
cache = new Map();
configCache.set(astroConfig, cache);
} else {
cache = configCache.get(astroConfig)!;
}
if (cache.has(filename)) {
return cache.get(filename)!;
}
const compileResult = await compile(props);
cache.set(filename, compileResult);
return compileResult;
}
202 changes: 80 additions & 122 deletions packages/astro/src/core/compile/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,150 +5,108 @@ import type { AstroConfig } from '../../@types/astro';
import { transform } from '@astrojs/compiler';
import { AggregateError, AstroError, CompilerError } from '../errors/errors.js';
import { AstroErrorData } from '../errors/index.js';
import { prependForwardSlash } from '../path.js';
import { resolvePath, viteID } from '../util.js';
import { resolvePath } from '../util.js';
import { createStylePreprocessor } from './style.js';

type CompilationCache = Map<string, CompileResult>;
type CompileResult = TransformResult & {
cssDeps: Set<string>;
source: string;
};

const configCache = new WeakMap<AstroConfig, CompilationCache>();

export interface CompileProps {
astroConfig: AstroConfig;
viteConfig: ResolvedConfig;
filename: string;
source: string;
}

async function compile({
export interface CompileResult extends TransformResult {
cssDeps: Set<string>;
source: string;
}

export async function compile({
astroConfig,
viteConfig,
filename,
source,
}: CompileProps): Promise<CompileResult> {
let cssDeps = new Set<string>();
let cssTransformErrors: AstroError[] = [];

// Transform from `.astro` to valid `.ts`
// use `sourcemap: "both"` so that sourcemap is included in the code
// result passed to esbuild, but also available in the catch handler.
const transformResult = await transform(source, {
pathname: filename,
projectRoot: astroConfig.root.toString(),
site: astroConfig.site?.toString(),
sourcefile: filename,
sourcemap: 'both',
internalURL: `/@fs${prependForwardSlash(
viteID(new URL('../../runtime/server/index.js', import.meta.url))
)}`,
// TODO: baseline flag
experimentalStaticExtraction: true,
preprocessStyle: createStylePreprocessor({
filename,
viteConfig,
cssDeps,
cssTransformErrors,
}),
async resolvePath(specifier) {
return resolvePath(specifier, filename);
},
})
.catch((err: Error) => {
// The compiler should be able to handle errors by itself, however
// for the rare cases where it can't let's directly throw here with as much info as possible
throw new CompilerError({
...AstroErrorData.UnknownCompilerError,
message: err.message ?? 'Unknown compiler error',
stack: err.stack,
location: {
file: filename,
},
});
})
.then((result) => {
const compilerError = result.diagnostics.find((diag) => diag.severity === 1);

if (compilerError) {
throw new CompilerError({
code: compilerError.code,
message: compilerError.text,
location: {
line: compilerError.location.line,
column: compilerError.location.column,
file: compilerError.location.file,
},
hint: compilerError.hint,
});
}
const cssDeps = new Set<string>();
const cssTransformErrors: AstroError[] = [];
let transformResult: TransformResult;

switch (cssTransformErrors.length) {
case 0:
return result;
case 1: {
let error = cssTransformErrors[0];
if (!error.errorCode) {
error.errorCode = AstroErrorData.UnknownCSSError.code;
}

throw cssTransformErrors[0];
}
default: {
throw new AggregateError({
...cssTransformErrors[0],
code: cssTransformErrors[0].errorCode,
errors: cssTransformErrors,
});
}
}
try {
// Transform from `.astro` to valid `.ts`
// use `sourcemap: "both"` so that sourcemap is included in the code
// result passed to esbuild, but also available in the catch handler.
transformResult = await transform(source, {
pathname: filename,
projectRoot: astroConfig.root.toString(),
site: astroConfig.site?.toString(),
sourcefile: filename,
sourcemap: 'both',
internalURL: 'astro/server/index.js',
// TODO: baseline flag
experimentalStaticExtraction: true,
preprocessStyle: createStylePreprocessor({
filename,
viteConfig,
cssDeps,
cssTransformErrors,
}),
async resolvePath(specifier) {
return resolvePath(specifier, filename);
},
});
} catch (err: any) {
// The compiler should be able to handle errors by itself, however
// for the rare cases where it can't let's directly throw here with as much info as possible
throw new CompilerError({
...AstroErrorData.UnknownCompilerError,
message: err.message ?? 'Unknown compiler error',
stack: err.stack,
location: {
file: filename,
},
});
}

const compileResult: CompileResult = Object.create(transformResult, {
cssDeps: {
value: cssDeps,
},
source: {
value: source,
},
});

return compileResult;
}
handleCompileResultErrors(transformResult, cssTransformErrors);

export function isCached(config: AstroConfig, filename: string) {
return configCache.has(config) && configCache.get(config)!.has(filename);
return {
...transformResult,
cssDeps,
source,
};
}

export function getCachedSource(config: AstroConfig, filename: string): string | null {
if (!isCached(config, filename)) return null;
let src = configCache.get(config)!.get(filename);
if (!src) return null;
return src.source;
}
function handleCompileResultErrors(result: TransformResult, cssTransformErrors: AstroError[]) {
const compilerError = result.diagnostics.find((diag) => diag.severity === 1);

export function invalidateCompilation(config: AstroConfig, filename: string) {
if (configCache.has(config)) {
const cache = configCache.get(config)!;
cache.delete(filename);
if (compilerError) {
throw new CompilerError({
code: compilerError.code,
message: compilerError.text,
location: {
line: compilerError.location.line,
column: compilerError.location.column,
file: compilerError.location.file,
},
hint: compilerError.hint,
});
}
}

export async function cachedCompilation(props: CompileProps): Promise<CompileResult> {
const { astroConfig, filename } = props;
let cache: CompilationCache;
if (!configCache.has(astroConfig)) {
cache = new Map();
configCache.set(astroConfig, cache);
} else {
cache = configCache.get(astroConfig)!;
}
if (cache.has(filename)) {
return cache.get(filename)!;
switch (cssTransformErrors.length) {
case 0:
break;
case 1: {
const error = cssTransformErrors[0];
if (!error.errorCode) {
error.errorCode = AstroErrorData.UnknownCSSError.code;
}
throw cssTransformErrors[0];
}
default: {
throw new AggregateError({
...cssTransformErrors[0],
code: cssTransformErrors[0].errorCode,
errors: cssTransformErrors,
});
}
}
const compileResult = await compile(props);
cache.set(filename, compileResult);
return compileResult;
}
9 changes: 7 additions & 2 deletions packages/astro/src/core/compile/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
export type { CompileProps } from './compile';
export { cachedCompilation, getCachedSource, invalidateCompilation, isCached } from './compile.js';
export {
cachedCompilation,
getCachedCompileResult,
invalidateCompilation,
isCached,
} from './cache.js';
export type { CompileProps, CompileResult } from './compile';
export type { TransformStyle } from './types';
2 changes: 2 additions & 0 deletions packages/astro/src/core/create-vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ export async function createVite(
},
],
conditions: ['astro'],
// Astro imports in third-party packages should use the same version as root
dedupe: ['astro'],
},
ssr: {
noExternal: [
Expand Down
Loading

0 comments on commit f536a34

Please sign in to comment.