Add svelte as a view engine to swaf #33
@ -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,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user