Add svelte as a view engine to swaf #33

Merged
ashpie merged 97 commits from svelte into develop 2021-11-09 19:31:22 +01:00
Showing only changes of commit eb6ed8f2d2 - Show all commits

View File

@ -7,7 +7,6 @@ import {promises as fs} from 'fs';
import path from "path"; import path from "path";
import requireFromString from "require-from-string"; import requireFromString from "require-from-string";
import {compile, preprocess} from "svelte/compiler"; import {compile, preprocess} from "svelte/compiler";
import {CssResult} from "svelte/types/compiler/interfaces";
import {sveltePreprocess} from "svelte-preprocess/dist/autoProcess.js"; import {sveltePreprocess} from "svelte-preprocess/dist/autoProcess.js";
import {logger} from "../Logger.js"; import {logger} from "../Logger.js";
@ -31,6 +30,7 @@ export default class SvelteViewEngine extends ViewEngine {
private readonly fileCache: FileCache = new FileCache(); private readonly fileCache: FileCache = new FileCache();
private readonly dependencyCache: Record<string, Set<string>> = {}; private readonly dependencyCache: Record<string, Set<string>> = {};
private readonly preprocessingCache: Record<string, PreprocessingCacheEntry> = {}; private readonly preprocessingCache: Record<string, PreprocessingCacheEntry> = {};
private readonly cssCache: Record<string, string[] | undefined> = {};
public constructor( public constructor(
targetDir: string, targetDir: string,
@ -96,24 +96,20 @@ export default class SvelteViewEngine extends ViewEngine {
} }
public async preCompile(canonicalName: string, alsoCompileDependents: boolean): Promise<void> { public async preCompile(canonicalName: string, alsoCompileDependents: boolean): Promise<void> {
const intermediateFile = path.join(this.targetDir, canonicalName); const targetFile = path.join(this.targetDir, canonicalName);
logger.info(canonicalName + ' > ', 'Pre-compiling', canonicalName, '->', targetFile);
logger.info(canonicalName + ' > ', 'Pre-compiling', canonicalName, '->', intermediateFile); const {backendCalls} = await this.preprocess(canonicalName);
const allBackendCalls: string[] = [];
const {backendCalls, code} = await this.preprocess(canonicalName);
allBackendCalls.push(...backendCalls);
// Server Side Render (initial HTML and CSS, no-js) // Server Side Render (initial HTML and CSS, no-js)
const ssr = await this.compileSsr(canonicalName, intermediateFile, code, allBackendCalls); const ssr = await this.compileSsr(canonicalName);
const separator = SvelteViewEngine.getPreCompileSeparator(canonicalName); const separator = SvelteViewEngine.getPreCompileSeparator(canonicalName);
const finalCode = [ const finalCode = [
[...new Set<string>(allBackendCalls).values()].join('\n'), [...new Set<string>(backendCalls).values()].join('\n'),
ssr.head, ssr.head,
ssr.html, ssr.html,
ssr.css.code, ssr.css,
].join(separator); ].join(separator);
const swafViewFile = path.join(this.targetDir, canonicalName + COMPILED_SVELTE_EXTENSION); const swafViewFile = path.join(this.targetDir, canonicalName + COMPILED_SVELTE_EXTENSION);
@ -261,18 +257,36 @@ export default class SvelteViewEngine extends ViewEngine {
}; };
} }
private async compileSsr(canonicalName: string, file: string, code: string, backendCalls: string[]): Promise<{ private async compileSsr(canonicalName: string): Promise<{
head: string, head: string,
css: CssResult, css: string,
html: string, html: string,
}> { }> {
const targetFile = path.join(this.targetDir, canonicalName);
const {backendCalls, code} = await this.preprocess(canonicalName);
// Get dependencies css
const dependenciesCss: string[] = [];
for (const dependency of this.resolveDependencies(code, canonicalName)) {
if (this.cssCache[dependency] === undefined) {
await this.compileSsr(dependency);
}
const css = this.cssCache[dependency];
if (css === undefined) {
logger.error(typeof this.cssCache[dependency], !!this.cssCache[dependency]);
throw new Error(`Compiling ssr of ${dependency} didn't cache its css.`);
}
dependenciesCss.push(...css);
}
logger.info(canonicalName + ' > ', 'Compiling svelte ssr', targetFile);
// Svelte compile // Svelte compile
logger.info(canonicalName + ' > ', 'Compiling svelte ssr', file);
const svelteSsr = compile(code, { const svelteSsr = compile(code, {
dev: config.get<boolean>('view.dev'), dev: config.get<boolean>('view.dev'),
generate: 'ssr', generate: 'ssr',
format: 'cjs', format: 'cjs',
cssOutputFilename: file + '.css', cssOutputFilename: targetFile + '.css',
}); });
// Load locals into locals store // Load locals into locals store
@ -287,9 +301,22 @@ export default class SvelteViewEngine extends ViewEngine {
}); });
// Load module and render // Load module and render
const moduleId = path.resolve(file); const moduleId = path.resolve(targetFile);
clearModule.single(moduleId); clearModule.single(moduleId);
return requireFromString(svelteSsr.js.code, moduleId).default.render(); const {
head,
css,
html,
} = requireFromString(svelteSsr.js.code, moduleId).default.render();
const cssFragments = css.code === '' ?
dependenciesCss :
[...dependenciesCss, css.code];
this.cssCache[canonicalName] = cssFragments;
return {
head,
css: [...new Set(cssFragments)].join(''),
html,
};
} }
private compileBackendCalls( private compileBackendCalls(