migrated to web workers for client side components
This commit is contained in:
parent
7dc55799b8
commit
a074952678
6 changed files with 476 additions and 214 deletions
14
README.md
14
README.md
|
@ -27,3 +27,17 @@ The dummies guide to maintaining a Next.js project:
|
|||
- Important: THIS IS NOT JAVASCRIPT! You CANNOT use global variables, window variables, etc, or even stateful variables that are meant to persist beyond a single refresh cycle (which can happen many times per second). Use the STATE for this (see [the module we are using for state management](https://github.com/pmndrs/zustand))
|
||||
- Try to define modules for your components instead of putting everything in one file to avoid JANK
|
||||
- You should put all static assets like images, icons, sound bytes, etc, in the `public` folder. These assets will be made available at the root directory `/`. For example, if `eecs-wordmark.png` is in `public`, then I can access it from an image element like so: `<img src="/eecs-wordmark.png" />`.
|
||||
- VERY IMPORTANT for performance and UI jank purposes:
|
||||
- As you may have noticed, we store all of our data in a super large TypeScript file at `db/data.ts`. This module contains exports for all of our 5 main "databases."
|
||||
- In order to access these databases from your components, there are two **critical** conventions to follow:
|
||||
- If your component is **server side**, then simply import the components like normal (eg `import { documents } from '@/app/db/data`) and use them in your code.
|
||||
- If your component is **client side**, then you should import the data using the utilities available in `db/loaders.ts`. The `loaders` library contains
|
||||
functions which return a Promise that resolve to the requested data. The function will load the very large objects in a separate thread via a Web Worker, which
|
||||
avoids blocking the main UI thread and freezing everything. You can then use the `useSuspenseQuery` hook from `@tanstack/react-query` to load this data in the background while
|
||||
triggering a React Suspense (if you don't set one up yourself, the default site wide loading bar will be used). This helps vastly reduce UI jank when trying to load the entire
|
||||
mega data object directly into memory.
|
||||
- Not sure whether you're in a client or server side component? If your component has the `'use client'` directive at the top of its file, then it's a client side component.
|
||||
Otherwise, by default, it should be a server side component.
|
||||
- Footnote: why don't I have to use the utilities in `db/loaders.ts` to asynchronously load the data in server side components?
|
||||
- Next.js will automatically pre-render all server side components into static HTML, which means there will be no performance impact (and in fact performance loss at build time)
|
||||
to loading the entire objects into memory.
|
||||
|
|
170
src/app/author/[author]/AuthorDisplay.tsx
Normal file
170
src/app/author/[author]/AuthorDisplay.tsx
Normal file
|
@ -0,0 +1,170 @@
|
|||
import Link from 'next/link'
|
||||
import { Fragment } from 'react'
|
||||
import { affiliations, nationalities, authors } from '../../db/data'
|
||||
import { Zilla_Slab } from 'next/font/google'
|
||||
|
||||
const zillaSlab = Zilla_Slab({ subsets: ['latin'], weight: ['500'] })
|
||||
|
||||
export default function AuthorDisplay({
|
||||
author,
|
||||
}: Readonly<{ author: string }>) {
|
||||
const data = authors[author]
|
||||
const { name, affiliation, image, nationality, formerAffiliations } = data
|
||||
|
||||
const MainPosition = () => {
|
||||
const mainAffiliationShort = affiliation[0].split('@')[1]
|
||||
const mainPosition = affiliation[0].split('@')[0]
|
||||
const mainAffiliation = affiliations[mainAffiliationShort]
|
||||
const { website } = data
|
||||
return (
|
||||
<>
|
||||
<span>{mainPosition} at </span>
|
||||
<Link href={`/affiliation/${mainAffiliationShort}`}>
|
||||
{mainAffiliation.name}
|
||||
</Link>
|
||||
{website ? (
|
||||
<div className='mt-2'>
|
||||
Visit {name.nickname ? name.nickname : name.first} at:{' '}
|
||||
<a href={website} target='_blank'>
|
||||
{website}
|
||||
</a>
|
||||
</div>
|
||||
) : null}
|
||||
<div className='my-4 max-h-12 flex flex-wrap'>
|
||||
{affiliation.map((a: string) => (
|
||||
<Link key={a} href={`/affiliation/${a.split('@')[1]}`}>
|
||||
<img
|
||||
src={affiliations[a.split('@')[1]].image}
|
||||
alt={affiliations[a.split('@')[1]].name}
|
||||
className='h-12 mr-2'
|
||||
/>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const OtherPositions = () => {
|
||||
if (affiliation.length === 1) return
|
||||
return (
|
||||
<>
|
||||
<h1 className='text-3xl md:mt-6 mt-4 mb-2 font-serif'>
|
||||
Other Positions:
|
||||
</h1>
|
||||
{affiliation.slice(1).map((a: string, i: number) => {
|
||||
const position = a.split('@')[0]
|
||||
const affiliation = affiliations[a.split('@')[1]].name
|
||||
return (
|
||||
<Fragment key={`${position}@${affiliation}`}>
|
||||
<span className='text-slate-500 text-lg'>
|
||||
{position} at{' '}
|
||||
<Link href={`/affiliation/${a.split('@')[1]}`}>
|
||||
{affiliation}
|
||||
</Link>
|
||||
</span>
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const FormerPositions = () => {
|
||||
if (!formerAffiliations) return null
|
||||
return (
|
||||
<>
|
||||
<h1 className='text-3xl md:mt-6 mt-4 mb-2 font-serif'>
|
||||
Former Positions:
|
||||
</h1>
|
||||
{formerAffiliations?.map((a: string, i: number) => {
|
||||
const position = a.split('@')[0]
|
||||
const affiliation = affiliations[a.split('@')[1]].name
|
||||
|
||||
return (
|
||||
<Fragment key={`${position}@${affiliation}`}>
|
||||
<span className='text-slate-500 text-lg'>
|
||||
{position} at{' '}
|
||||
<Link href={`/affiliation/${a.split('@')[1]}`}>
|
||||
{affiliation}
|
||||
</Link>
|
||||
</span>
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const NationalityDisplay = ({
|
||||
nationality,
|
||||
}: Readonly<{ nationality: string }>) => {
|
||||
const nationalityData = nationalities[nationality]
|
||||
const { demonym, flag } = nationalityData
|
||||
return (
|
||||
<div className='flex items-center'>
|
||||
<img
|
||||
src={flag}
|
||||
className='w-10 border-2 border-slate-200'
|
||||
alt={`${demonym} flag`}
|
||||
/>
|
||||
<span className='mx-3 font-semibold'>{demonym}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Bio = () => {
|
||||
const { bio } = data
|
||||
if (!bio) return null
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1 className='text-3xl md:mt-6 mt-4 mb-2 font-serif'>Bio:</h1>
|
||||
<p>{bio}</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='grid grid-cols-1 md:grid-cols-2 items-center max-w-3xl mx-auto'>
|
||||
<div className='aspect-square w-[60vw] md:w-[30vw] lg:w-[20vw] 2xl:w-[15vw] overflow-hidden mx-auto mb-4'>
|
||||
<img
|
||||
alt='profile'
|
||||
className='rounded-full mx-auto object-cover w-full h-full border-slate-800 border-4'
|
||||
src={image}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<span
|
||||
className={`${zillaSlab.className} font-bold text-5xl text-center md:text-left`}
|
||||
>
|
||||
{name.first}
|
||||
{name.nickname ? ` "${name.nickname}"` : null} {name.last}
|
||||
</span>
|
||||
<div className='text-slate-600 text-md sm:text-lg mt-4'>
|
||||
<MainPosition />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='max-w-3xl mx-auto grid grid-cols-1 justify-center'>
|
||||
<hr className='mx-auto w-full h-1 border-0 bg-slate-200 my-2 rounded-md' />
|
||||
<OtherPositions />
|
||||
<FormerPositions />
|
||||
<h1 className='text-3xl md:my-6 my-4 font-serif'>
|
||||
Ethnicity and Nationality:
|
||||
</h1>
|
||||
<div className='flex gap-2 flex-wrap'>
|
||||
{nationality.map((n: string) => (
|
||||
<Fragment key={n}>
|
||||
<NationalityDisplay nationality={n} />
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
<Bio />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,10 +1,5 @@
|
|||
import { authors, affiliations, nationalities } from '../../db/data'
|
||||
import { Zilla_Slab } from 'next/font/google'
|
||||
import Link from 'next/link'
|
||||
import { notFound } from 'next/navigation'
|
||||
import { Fragment, Suspense } from 'react'
|
||||
|
||||
const zillaSlab = Zilla_Slab({ subsets: ['latin'], weight: ['500'] })
|
||||
import AuthorDisplay from './AuthorDisplay'
|
||||
import { authors } from '@/app/db/data'
|
||||
|
||||
export function generateStaticParams() {
|
||||
const authorsList = Object.keys(authors)
|
||||
|
@ -16,172 +11,5 @@ export default function Page({
|
|||
}: Readonly<{
|
||||
params: { author: string }
|
||||
}>) {
|
||||
const authorData = authors[params.author]
|
||||
// console.log(authorData)
|
||||
if (!authorData) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
const { name, affiliation, image, nationality, formerAffiliations } =
|
||||
authorData
|
||||
|
||||
const MainPosition = () => {
|
||||
const mainAffiliationShort = affiliation[0].split('@')[1]
|
||||
const mainPosition = affiliation[0].split('@')[0]
|
||||
const mainAffiliation = affiliations[mainAffiliationShort]
|
||||
return (
|
||||
<>
|
||||
<span>{mainPosition} at </span>
|
||||
<Link href={`/affiliation/${mainAffiliationShort}`}>
|
||||
{mainAffiliation.name}
|
||||
</Link>
|
||||
{authorData.website ? (
|
||||
<div className='mt-2'>
|
||||
Visit{' '}
|
||||
{authorData.name.nickname
|
||||
? authorData.name.nickname
|
||||
: authorData.name.first}{' '}
|
||||
at:{' '}
|
||||
<a href={authorData.website} target='_blank'>
|
||||
{authorData.website}
|
||||
</a>
|
||||
</div>
|
||||
) : null}
|
||||
<div className='my-4 max-h-12 flex flex-wrap'>
|
||||
{affiliation.map((a: string) => (
|
||||
<Link key={a} href={`/affiliation/${a.split('@')[1]}`}>
|
||||
<img
|
||||
src={affiliations[a.split('@')[1]].image}
|
||||
alt={affiliations[a.split('@')[1]].name}
|
||||
className='h-12 mr-2'
|
||||
/>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const OtherPositions = () => {
|
||||
if (affiliation.length === 1) return
|
||||
return (
|
||||
<>
|
||||
<h1 className='text-3xl md:mt-6 mt-4 mb-2 font-serif'>
|
||||
Other Positions:
|
||||
</h1>
|
||||
{affiliation.slice(1).map((a: string, i: number) => {
|
||||
const position = a.split('@')[0]
|
||||
const affiliation = affiliations[a.split('@')[1]].name
|
||||
return (
|
||||
<Fragment key={`${position}@${affiliation}`}>
|
||||
<span className='text-slate-500 text-lg'>
|
||||
{position} at{' '}
|
||||
<Link href={`/affiliation/${a.split('@')[1]}`}>
|
||||
{affiliation}
|
||||
</Link>
|
||||
</span>
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const FormerPositions = () => {
|
||||
if (!formerAffiliations) return null
|
||||
return (
|
||||
<>
|
||||
<h1 className='text-3xl md:mt-6 mt-4 mb-2 font-serif'>
|
||||
Former Positions:
|
||||
</h1>
|
||||
{formerAffiliations?.map((a: string, i: number) => {
|
||||
const position = a.split('@')[0]
|
||||
const affiliation = affiliations[a.split('@')[1]].name
|
||||
|
||||
return (
|
||||
<Fragment key={`${position}@${affiliation}`}>
|
||||
<span className='text-slate-500 text-lg'>
|
||||
{position} at{' '}
|
||||
<Link href={`/affiliation/${a.split('@')[1]}`}>
|
||||
{affiliation}
|
||||
</Link>
|
||||
</span>
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const NationalityDisplay = ({
|
||||
nationality,
|
||||
}: Readonly<{ nationality: string }>) => {
|
||||
const nationalityData = nationalities[nationality]
|
||||
const { demonym, flag } = nationalityData
|
||||
return (
|
||||
<div className='flex items-center'>
|
||||
<img
|
||||
src={flag}
|
||||
className='w-10 border-2 border-slate-200'
|
||||
alt={`${demonym} flag`}
|
||||
/>
|
||||
<span className='mx-3 font-semibold'>{demonym}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Bio = () => {
|
||||
const { bio } = authorData
|
||||
if (!bio) return null
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1 className='text-3xl md:mt-6 mt-4 mb-2 font-serif'>Bio:</h1>
|
||||
<p>{authorData.bio}</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='grid grid-cols-1 md:grid-cols-2 items-center max-w-3xl mx-auto'>
|
||||
<div className='aspect-square w-[60vw] md:w-[30vw] lg:w-[20vw] 2xl:w-[15vw] overflow-hidden mx-auto mb-4'>
|
||||
<img
|
||||
alt='profile'
|
||||
className='rounded-full mx-auto object-cover w-full h-full border-slate-800 border-4'
|
||||
src={image}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<span
|
||||
className={`${zillaSlab.className} font-bold text-5xl text-center md:text-left`}
|
||||
>
|
||||
{name.first}
|
||||
{name.nickname ? ` "${name.nickname}"` : null} {name.last}
|
||||
</span>
|
||||
<div className='text-slate-600 text-md sm:text-lg mt-4'>
|
||||
<MainPosition />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='max-w-3xl mx-auto grid grid-cols-1 justify-center'>
|
||||
<hr className='mx-auto w-full h-1 border-0 bg-slate-200 my-2 rounded-md' />
|
||||
<OtherPositions />
|
||||
<FormerPositions />
|
||||
<h1 className='text-3xl md:my-6 my-4 font-serif'>
|
||||
Ethnicity and Nationality:
|
||||
</h1>
|
||||
<div className='flex gap-2 flex-wrap'>
|
||||
{nationality.map((n: string) => (
|
||||
<Fragment key={n}>
|
||||
<NationalityDisplay nationality={n} />
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
<Bio />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
return <AuthorDisplay author={params.author} />
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import { Fragment } from 'react'
|
||||
import Link from 'next/link'
|
||||
import {
|
||||
topics as topicList,
|
||||
authors as authorList,
|
||||
reviewer,
|
||||
} from '@/app/db/data'
|
||||
import { reviewer } from '@/app/db/data'
|
||||
import { loadAllTopics, loadAllAuthors } from '@/app/db/loaders'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
|
||||
export const Code = ({
|
||||
code,
|
||||
|
@ -54,6 +52,18 @@ export const Topics = ({
|
|||
topics,
|
||||
showTitle = true,
|
||||
}: Readonly<{ topics: string[]; showTitle?: boolean }>) => {
|
||||
'use client'
|
||||
|
||||
const { data, error } = useSuspenseQuery({
|
||||
queryKey: ['topics_all'],
|
||||
queryFn: () => {
|
||||
const data = loadAllTopics()
|
||||
return data
|
||||
},
|
||||
})
|
||||
if (error) throw error
|
||||
const topicList = data
|
||||
|
||||
return (
|
||||
<>
|
||||
{showTitle ? <span className='font-bold'>Topics: </span> : null}
|
||||
|
@ -72,6 +82,19 @@ export const Topics = ({
|
|||
export const Authors = ({
|
||||
authors,
|
||||
}: Readonly<{ authors: string[]; noLink?: boolean }>) => {
|
||||
'use client'
|
||||
|
||||
const { data, error } = useSuspenseQuery({
|
||||
queryKey: ['authors_all'],
|
||||
queryFn: () => {
|
||||
const data = loadAllAuthors()
|
||||
return data
|
||||
},
|
||||
})
|
||||
if (error) throw error
|
||||
|
||||
const authorList = data
|
||||
|
||||
return (
|
||||
<>
|
||||
{authors.map((a: string, i) => (
|
||||
|
@ -95,20 +118,16 @@ export const Reviewers = ({
|
|||
const ReviewerDisplay = ({ r }: Readonly<{ r: reviewer }>) => {
|
||||
if (r.profile) {
|
||||
return (
|
||||
<>
|
||||
<Link href={`/author/${r.profile}`} target='_blank'>
|
||||
{r.first} {r.last}
|
||||
</Link>
|
||||
</>
|
||||
<Link href={`/author/${r.profile}`} target='_blank'>
|
||||
{r.first} {r.last}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
if (r.url) {
|
||||
return (
|
||||
<>
|
||||
<a href={r.url} target='_blank'>
|
||||
{r.first} {r.last}
|
||||
</a>
|
||||
</>
|
||||
<a href={r.url} target='_blank'>
|
||||
{r.first} {r.last}
|
||||
</a>
|
||||
)
|
||||
}
|
||||
return (
|
||||
|
|
|
@ -282,14 +282,12 @@ On Day 1 we will discuss the ins and outs of the robot. The Electrical Sub team
|
|||
},
|
||||
}
|
||||
|
||||
export interface Topics {
|
||||
[key: string]: {
|
||||
name: string
|
||||
description: string
|
||||
wiki: string
|
||||
}
|
||||
export interface Topic {
|
||||
name: string
|
||||
description: string
|
||||
wiki: string
|
||||
}
|
||||
export const topics: Topics = {
|
||||
export const topics: { [key: string]: Topic } = {
|
||||
frc: {
|
||||
name: 'FIRST Robotics Competition',
|
||||
description:
|
||||
|
@ -499,16 +497,14 @@ export const authors: { [key: string]: Author } = {
|
|||
},
|
||||
}
|
||||
|
||||
export interface Affiliations {
|
||||
[key: string]: {
|
||||
name: string
|
||||
short: string
|
||||
image: string
|
||||
description: string
|
||||
}
|
||||
export interface Affiliation {
|
||||
name: string
|
||||
short: string
|
||||
image: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export const affiliations: Affiliations = {
|
||||
export const affiliations: { [key: string]: Affiliation } = {
|
||||
'1280-mech': {
|
||||
name: "Team 1280, the Ragin' C Biscuits, Mechanical Subteam",
|
||||
short: '1280 Mech',
|
||||
|
@ -659,14 +655,12 @@ Raid Zero's influence extends beyond the technical achievements in robotics comp
|
|||
},
|
||||
}
|
||||
|
||||
export interface Nationalities {
|
||||
[key: string]: {
|
||||
name: string
|
||||
demonym: string
|
||||
flag: string
|
||||
}
|
||||
export interface Nationality {
|
||||
name: string
|
||||
demonym: string
|
||||
flag: string
|
||||
}
|
||||
export const nationalities: Nationalities = {
|
||||
export const nationalities: { [key: string]: Nationality } = {
|
||||
pak: {
|
||||
name: 'Pakistan',
|
||||
demonym: 'Pakistani',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Document, Author } from './data'
|
||||
import { Document, Author, Affiliation, Topic, Nationality } from './data'
|
||||
|
||||
export const loadDocument = (id: string): Promise<Document> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -67,7 +67,7 @@ export const loadAllAuthors = (): Promise<{ [key: string]: Author }> => {
|
|||
return new Promise((resolve, reject) => {
|
||||
if (typeof Worker !== 'undefined') {
|
||||
const worker = new Worker(
|
||||
new URL('./workers/documentLoader.worker.ts', import.meta.url),
|
||||
new URL('./workers/authorLoader.worker.ts', import.meta.url),
|
||||
{ type: 'module' }
|
||||
)
|
||||
|
||||
|
@ -91,3 +91,240 @@ export const loadAllAuthors = (): Promise<{ [key: string]: Author }> => {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const loadAuthor = (id: string): Promise<Author> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof Worker !== 'undefined') {
|
||||
const worker = new Worker(
|
||||
new URL('./workers/authorLoader.worker.ts', import.meta.url),
|
||||
{ type: 'module' }
|
||||
)
|
||||
|
||||
worker.onmessage = (e: MessageEvent<{ [key: string]: Author }>) => {
|
||||
const data = e.data
|
||||
const author: Author | undefined = data[id]
|
||||
if (!author) {
|
||||
return reject(new Error('404'))
|
||||
} else {
|
||||
resolve(author)
|
||||
}
|
||||
worker.terminate()
|
||||
}
|
||||
|
||||
worker.onerror = (error) => {
|
||||
reject(error)
|
||||
worker.terminate()
|
||||
}
|
||||
|
||||
worker.postMessage('LOAD')
|
||||
} else {
|
||||
reject(
|
||||
new Error(
|
||||
`Web Workers are not supported in this environment. Please avoid using a prehistoric browser.
|
||||
If nothing else seems wrong, this error message is probably showing up due to ghosts in your browser.`
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const loadAffiliation = (id: string): Promise<Affiliation> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof Worker !== 'undefined') {
|
||||
const worker = new Worker(
|
||||
new URL('./workers/affiliationLoader.worker.ts', import.meta.url),
|
||||
{ type: 'module' }
|
||||
)
|
||||
|
||||
worker.onmessage = (e: MessageEvent<{ [key: string]: Affiliation }>) => {
|
||||
const data = e.data
|
||||
const affiliation: Affiliation | undefined = data[id]
|
||||
if (!affiliation) {
|
||||
return reject(new Error('404'))
|
||||
} else {
|
||||
resolve(affiliation)
|
||||
}
|
||||
worker.terminate()
|
||||
}
|
||||
|
||||
worker.onerror = (error) => {
|
||||
reject(error)
|
||||
worker.terminate()
|
||||
}
|
||||
|
||||
worker.postMessage('LOAD')
|
||||
} else {
|
||||
reject(
|
||||
new Error(
|
||||
`Web Workers are not supported in this environment. Please avoid using a prehistoric browser.
|
||||
If nothing else seems wrong, this error message is probably showing up due to ghosts in your browser.`
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const loadAllAffiliations = (): Promise<{
|
||||
[key: string]: Affiliation
|
||||
}> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof Worker !== 'undefined') {
|
||||
const worker = new Worker(
|
||||
new URL('./workers/affiliationLoader.worker.ts', import.meta.url),
|
||||
{ type: 'module' }
|
||||
)
|
||||
|
||||
worker.onmessage = (e: MessageEvent<{ [key: string]: Affiliation }>) => {
|
||||
resolve(e.data)
|
||||
worker.terminate()
|
||||
}
|
||||
|
||||
worker.onerror = (error) => {
|
||||
reject(error)
|
||||
worker.terminate()
|
||||
}
|
||||
|
||||
worker.postMessage('LOAD')
|
||||
} else {
|
||||
reject(
|
||||
new Error(
|
||||
'Web Workers are not supported in this environment. Please avoid using a prehistoric browser.'
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const loadTopic = (id: string): Promise<Topic> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof Worker !== 'undefined') {
|
||||
const worker = new Worker(
|
||||
new URL('./workers/topicLoader.worker.ts', import.meta.url),
|
||||
{ type: 'module' }
|
||||
)
|
||||
|
||||
worker.onmessage = (e: MessageEvent<{ [key: string]: Topic }>) => {
|
||||
const data = e.data
|
||||
const topic: Topic | undefined = data[id]
|
||||
if (!topic) {
|
||||
return reject(new Error('404'))
|
||||
} else {
|
||||
resolve(topic)
|
||||
}
|
||||
worker.terminate()
|
||||
}
|
||||
|
||||
worker.onerror = (error) => {
|
||||
reject(error)
|
||||
worker.terminate()
|
||||
}
|
||||
|
||||
worker.postMessage('LOAD')
|
||||
} else {
|
||||
reject(
|
||||
new Error(
|
||||
`Web Workers are not supported in this environment. Please avoid using a prehistoric browser.
|
||||
If nothing else seems wrong, this error message is probably showing up due to ghosts in your browser.`
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const loadAllTopics = (): Promise<{
|
||||
[key: string]: Topic
|
||||
}> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof Worker !== 'undefined') {
|
||||
const worker = new Worker(
|
||||
new URL('./workers/topicLoader.worker.ts', import.meta.url),
|
||||
{ type: 'module' }
|
||||
)
|
||||
|
||||
worker.onmessage = (e: MessageEvent<{ [key: string]: Topic }>) => {
|
||||
resolve(e.data)
|
||||
worker.terminate()
|
||||
}
|
||||
|
||||
worker.onerror = (error) => {
|
||||
reject(error)
|
||||
worker.terminate()
|
||||
}
|
||||
|
||||
worker.postMessage('LOAD')
|
||||
} else {
|
||||
reject(
|
||||
new Error(
|
||||
'Web Workers are not supported in this environment. Please avoid using a prehistoric browser.'
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const loadNationality = (id: string): Promise<Nationality> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof Worker !== 'undefined') {
|
||||
const worker = new Worker(
|
||||
new URL('./workers/nationalityLoader.worker.ts', import.meta.url),
|
||||
{ type: 'module' }
|
||||
)
|
||||
|
||||
worker.onmessage = (e: MessageEvent<{ [key: string]: Nationality }>) => {
|
||||
const data = e.data
|
||||
const nationality: Nationality | undefined = data[id]
|
||||
if (!nationality) {
|
||||
return reject(new Error('404'))
|
||||
} else {
|
||||
resolve(nationality)
|
||||
}
|
||||
worker.terminate()
|
||||
}
|
||||
|
||||
worker.onerror = (error) => {
|
||||
reject(error)
|
||||
worker.terminate()
|
||||
}
|
||||
|
||||
worker.postMessage('LOAD')
|
||||
} else {
|
||||
reject(
|
||||
new Error(
|
||||
`Web Workers are not supported in this environment. Please avoid using a prehistoric browser.
|
||||
If nothing else seems wrong, this error message is probably showing up due to ghosts in your browser.`
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const loadAllNationalities = (): Promise<{
|
||||
[key: string]: Nationality
|
||||
}> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof Worker !== 'undefined') {
|
||||
const worker = new Worker(
|
||||
new URL('./workers/topicLoader.worker.ts', import.meta.url),
|
||||
{ type: 'module' }
|
||||
)
|
||||
|
||||
worker.onmessage = (e: MessageEvent<{ [key: string]: Nationality }>) => {
|
||||
resolve(e.data)
|
||||
worker.terminate()
|
||||
}
|
||||
|
||||
worker.onerror = (error) => {
|
||||
reject(error)
|
||||
worker.terminate()
|
||||
}
|
||||
|
||||
worker.postMessage('LOAD')
|
||||
} else {
|
||||
reject(
|
||||
new Error(
|
||||
'Web Workers are not supported in this environment. Please avoid using a prehistoric browser.'
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue