Skip to content

Instantly share code, notes, and snippets.

@seantiz
Last active June 4, 2025 17:02
Show Gist options
  • Save seantiz/9eb34ec975007b70c8e7aa37d6d3cdbe to your computer and use it in GitHub Desktop.
Save seantiz/9eb34ec975007b70c8e7aa37d6d3cdbe to your computer and use it in GitHub Desktop.
Root +page.ts loader (browser guard + dynamic importing)
import type { PageLoad } from './$types';
import { writable, type Writable } from 'svelte/store';
// Ignore this - config from my old project
import {
PUBLIC_FILES_PATH,
PUBLIC_SAVED_CONFIG,
PUBLIC_NODE_ENV,
PUBLIC_SAVED_JOBDESC
} from '$env/static/public';
// Ignore this - project-specific types
import type { Job, Stats } from '$lib';
// 1. Import our source modules but we'll defer initialising them until later
import { allJobs, fetchedTotal, appliedTotal } from '$lib/jobHistory';
import { currentCV, currentLetter, nextJobApplication, nextJobDetails } from '$lib/jobApplication';
const dev = PUBLIC_NODE_ENV === 'development';
// 2. Setup the dynamic loading
const jobhunterlib: Promise<any> =
typeof window !== 'undefined' // 3. Guard against initialising any code before the browser's DOM is ready
? import('$lib/jobIO').then((module) => module.jobhunter)
: new Promise(() => ({}));
const getLoadApplicantConfig: Promise<() => Promise<any>> =
typeof window !== 'undefined'
? import('$lib/jobIO').then((module) => module.loadApplicantConfig)
: new Promise(() => () => Promise.resolve({}));
let initialised: Writable<boolean> = writable(false); // 4. Boolean flag guard - in hindsight probably not needed
// 5. The page.ts universal loader
export const load = (async () => {
if (typeof window !== 'undefined') {
initialiseApp();
}
return {
initialised
};
}) satisfies PageLoad;
// 6. Safe helper for the universal loader - manages loading all the deferred code before returning it to the universal load function
async function initialiseApp() {
const jobhunter = await jobhunterlib;
// jobhunter.startServer();
async function readLetterParams(): Promise<string> {
if (dev) {
const config = await jobhunter.resolvePath(PUBLIC_FILES_PATH, PUBLIC_SAVED_CONFIG);
const content = await jobhunter.read(config);
return JSON.parse(content).coverLetter || '';
} else {
const content = (await jobhunter.tauriCommand('read_config')) as string;
return JSON.parse(content).coverLetter || '';
}
}
async function getLastSavedJob(): Promise<string> {
if (dev) {
const jobDescPath = await jobhunter.resolvePath(PUBLIC_FILES_PATH, PUBLIC_SAVED_JOBDESC);
const content = await jobhunter.read(jobDescPath);
return content || '';
} else {
return ((await jobhunter.tauriCommand('read_job_description')) as string) || '';
}
}
async function readConfig(): Promise<string> {
try {
if (dev) {
const configPath = await jobhunter.resolvePath(PUBLIC_FILES_PATH, PUBLIC_SAVED_CONFIG);
return await jobhunter.read(configPath);
} else {
return (await jobhunter.tauriCommand('read_config')) as string;
}
} catch (error) {
console.error('Error reading config:', error);
await jobhunter.showMessage(`Failed to read config: ${error}`, {
title: 'Error',
type: 'error'
});
return '{}'; // Return empty object as string
}
}
async function loadAppData() {
try {
const loadApplicantConfig = await getLoadApplicantConfig;
const applicantDetails = await loadApplicantConfig();
const lastSavedJob = await getLastSavedJob();
const coverLetter = await readLetterParams();
// Load job description
let jobDescription;
try {
jobDescription = JSON.parse(lastSavedJob);
} catch (error) {
console.error('Error parsing job description:', error);
jobDescription = {};
}
nextJobDetails.set({ ...nextJobDetails, ...jobDescription });
// Load applicant details
let parsedApplicantDetails;
try {
if (dev) {
parsedApplicantDetails = applicantDetails;
} else {
const applicantDetailsStr = (await jobhunter.tauriCommand(
'read_applicant_details'
)) as string;
parsedApplicantDetails = JSON.parse(applicantDetailsStr);
}
} catch (error) {
console.error('Error loading applicant details:', error);
parsedApplicantDetails = {};
}
nextJobApplication.set({ ...nextJobApplication, ...parsedApplicantDetails });
currentLetter.set(coverLetter);
const config = await readConfig();
currentCV.set(JSON.parse(config).cvFilename);
const [jobs, stats] = await Promise.all([
jobhunter.tauriCommand('get_unread_jobs') as Promise<Job[]>,
jobhunter.tauriCommand('get_stats') as Promise<Stats>
]);
allJobs.set(jobs);
if (stats) {
fetchedTotal.set(stats.uniquejobs);
appliedTotal.set(stats.appliedjobs);
} else {
await jobhunter.showMessage('No stats data received', { title: 'Warning', type: 'error' });
}
} catch (error) {
console.error('Error in loadAppData:', error);
fetchedTotal.set(0);
appliedTotal.set(0);
await jobhunter.showMessage('Failed to initialize app.', { title: 'Error', type: 'error' });
}
}
try {
await loadAppData();
initialised.set(true);
} catch (error) {
await jobhunter.showMessage('Failed to initialize app.', { title: 'Error', type: 'error' });
initialised.set(true);
}
}
export const ssr = false;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment