Svelte: write fully preprocessed code to pre-compiled files

This commit is contained in:
Alice Gaudon 2021-05-11 13:52:48 +02:00
parent e95595f5a3
commit 42f7ebba05

View File

@ -30,10 +30,7 @@ export default class SvelteViewEngine extends ViewEngine {
private readonly fileCache: FileCache = new FileCache();
private readonly dependencyCache: Record<string, Set<string>> = {};
private readonly backendCallsCache: Record<string, {
replacedBackendCall: string,
backendCalls: string[],
}> = {};
private readonly preprocessingCache: Record<string, PreprocessingCacheEntry> = {};
public constructor(
targetDir: string,
@ -43,12 +40,12 @@ export default class SvelteViewEngine extends ViewEngine {
}
public async onFileChange(file: string): Promise<void> {
delete this.backendCallsCache[this.toCanonicalName(file)];
delete this.preprocessingCache[this.toCanonicalName(file)];
}
public async onFileRemove(file: string): Promise<void> {
const canonicalName = this.toCanonicalName(file);
delete this.backendCallsCache[canonicalName];
delete this.preprocessingCache[canonicalName];
delete this.dependencyCache[canonicalName];
Object.values(this.dependencyCache).forEach(set => set.delete(canonicalName));
await super.onFileRemove(file);
@ -124,14 +121,14 @@ export default class SvelteViewEngine extends ViewEngine {
const allBackendCalls: string[] = [];
for (const dependency of this.resolveDependencies(source, canonicalName)) {
allBackendCalls.push(...(await this.replaceBackendCalls(dependency)).backendCalls);
allBackendCalls.push(...(await this.preprocess(dependency)).backendCalls);
}
const {replacedBackendCall, backendCalls} = await this.replaceBackendCalls(canonicalName, source);
const {backendCalls, code} = await this.preprocess(canonicalName, source);
allBackendCalls.push(...backendCalls);
// Server Side Render (initial HTML and CSS, no-js)
const ssr = await this.compileSsr(canonicalName, intermediateFile, replacedBackendCall);
const ssr = await this.compileSsr(canonicalName, intermediateFile, code);
const separator = SvelteViewEngine.getPreCompileSeparator(canonicalName);
const finalCode = [
@ -176,34 +173,59 @@ export default class SvelteViewEngine extends ViewEngine {
return dependencies;
}
private async replaceBackendCalls(canonicalViewName: string, code?: string): Promise<{
replacedBackendCall: string,
backendCalls: string[],
}> {
private async preprocess(canonicalName: string, code?: string): Promise<PreprocessingCacheEntry> {
// Cache
if (Object.keys(this.backendCallsCache).indexOf(canonicalViewName) >= 0) {
return this.backendCallsCache[canonicalViewName];
if (Object.keys(this.preprocessingCache).indexOf(canonicalName) >= 0) {
return this.preprocessingCache[canonicalName];
}
const file = await this.resolveFileFromCanonicalName(canonicalName);
logger.info(canonicalName + ' > ', `Preprocessing ${file}`);
// mkdir output file dir
const outputFile = path.join(this.targetDir, canonicalViewName);
const outputFile = path.join(this.targetDir, canonicalName);
await fs.mkdir(path.dirname(outputFile), {recursive: true});
// Read source file if code was not already provided
if (!code) {
const file = await this.resolveFileFromCanonicalName(canonicalViewName);
code = await this.fileCache.get(file, !config.get<boolean>('view.cache'));
}
// Replace backend calls
const replacedBackendCalls = await this.replaceBackendCalls(canonicalName, code);
// Preprocess svelte
logger.info(canonicalName + ' > ', 'Svelte preprocessing');
const preprocessed = await preprocess(
replacedBackendCalls.code,
sveltePreprocess({
typescript: {
tsconfigFile: 'tsconfig.svelte.json',
},
}),
{
filename: outputFile,
},
);
// Write to output file
await fs.writeFile(outputFile, preprocessed.code);
return this.preprocessingCache[canonicalName] = {
backendCalls: replacedBackendCalls.backendCalls,
code: preprocessed.code,
};
}
private async replaceBackendCalls(canonicalName: string, code: string): Promise<PreprocessingCacheEntry> {
logger.info(canonicalName + ' > ', 'Replacing backend calls');
// Skip replace if there is no swaf export
if (!code.match(/export[ \n]+let[ \n]+locals[ \n]*=[ \n]*{[ \n]*}/)) {
const generated = {
replacedBackendCall: code,
return {
backendCalls: [],
code: code,
};
await fs.writeFile(outputFile, generated.replacedBackendCall);
this.backendCallsCache[canonicalViewName] = generated;
return generated;
}
@ -251,14 +273,10 @@ export default class SvelteViewEngine extends ViewEngine {
}
output = output.split(BACKEND_CODE_PREFIX_TEMPORARY_HOLDER).join(BACKEND_CODE_PREFIX);
const generated = {
replacedBackendCall: output,
return {
backendCalls: [...backendCalls],
code: output,
};
await fs.writeFile(outputFile, generated.replacedBackendCall);
this.backendCallsCache[canonicalViewName] = generated;
return generated;
}
private async compileSsr(canonicalName: string, file: string, code: string): Promise<{
@ -266,23 +284,9 @@ export default class SvelteViewEngine extends ViewEngine {
css: CssResult,
html: string,
}> {
// Svelte preprocess
logger.info(canonicalName + ' > ', 'Preprocessing svelte', file);
const preprocessed = await preprocess(
code,
sveltePreprocess({
typescript: {
tsconfigFile: 'tsconfig.svelte.json',
},
}),
{
filename: file,
},
);
// Svelte compile
logger.info(canonicalName + ' > ', 'Compiling svelte ssr', file);
const svelteSsr = compile(preprocessed.code, {
const svelteSsr = compile(code, {
dev: config.get<boolean>('view.dev'),
generate: 'ssr',
format: 'cjs',
@ -299,3 +303,7 @@ export default class SvelteViewEngine extends ViewEngine {
}
}
type PreprocessingCacheEntry = {
backendCalls: string[],
code: string,
};