1- import { mkdir , readFile , writeFile } from 'fs/promises' ;
1+ import { prerender , type PrerenderRoute } from '@cutting/devtools/prerender.js' ;
2+ import { readFile } from 'fs/promises' ;
23import { dirname , join } from 'path' ;
34import { fileURLToPath } from 'url' ;
45
@@ -14,66 +15,22 @@ const DEFAULT_META = {
1415 'https://res.cloudinary.com/ddospxsc8/image/upload/w_1000,ar_16:9,c_fill,g_auto,e_sharpen/v1767264044/rescue_dieu8h.png' ,
1516} ;
1617
17- type Meta = { title : string ; description : string ; image : string } ;
18- type Post = { slug : string ; title : string ; description : string } ;
19-
2018const STATIC_ROUTES = [ '/' , '/about' , '/contact' , '/email/confirmation' , '/posts' , '/testimonials' ] ;
2119
22- async function posts ( ) : Promise < Post [ ] > {
23- const listPath = join ( clientDir , 'posts' , 'posts-list.json' ) ;
24- return JSON . parse ( await readFile ( listPath , 'utf-8' ) ) as Post [ ] ;
25- }
26-
27- function outputPath ( route : string ) : string {
28- const segment = route === '/' ? '' : route ;
29- return join ( clientDir , segment , 'index.html' ) ;
30- }
31-
32- function setMeta ( html : string , key : string , value : string ) : string {
33- const re = new RegExp ( `(="${ key } " content=")[^"]*(")` ) ;
34- return html . replace ( re , ( _match , before : string , after : string ) => `${ before } ${ value } ${ after } ` ) ;
35- }
36-
37- async function prerender ( ) : Promise < void > {
38- const template = await readFile ( join ( clientDir , 'index.html' ) , 'utf-8' ) ;
39-
40- const routeMeta = new Map < string , Meta > ( STATIC_ROUTES . map ( ( route ) => [ route , DEFAULT_META ] ) ) ;
41- for ( const post of await posts ( ) ) {
42- routeMeta . set ( `/posts/${ post . slug } ` , {
43- title : post . title ,
44- description : post . description || DEFAULT_META . description ,
45- image : `${ BASE_URL } /og/${ post . slug } .png` ,
46- } ) ;
47- }
48-
49- for ( const [ route , meta ] of routeMeta ) {
50- const values : Record < string , string > = {
51- 'og:url' : `${ BASE_URL } ${ route } ` ,
52- 'twitter:url' : `${ BASE_URL } ${ route } ` ,
53- 'og:title' : meta . title ,
54- 'og:image:alt' : meta . title ,
55- 'twitter:title' : meta . title ,
56- 'og:description' : meta . description ,
57- 'twitter:description' : meta . description ,
58- 'og:image' : meta . image ,
59- 'twitter:image:src' : meta . image ,
60- } ;
20+ type Post = { slug : string ; title : string ; description : string } ;
6121
62- let html = template ;
63- for ( const [ key , value ] of Object . entries ( values ) ) {
64- html = setMeta ( html , key , value ) ;
65- }
66- html = html . replace ( / < t i t l e > [ ^ < ] * < \/ t i t l e > / , `<title>${ meta . title } </title>` ) ;
22+ async function routes ( ) : Promise < PrerenderRoute [ ] > {
23+ const list = JSON . parse ( await readFile ( join ( clientDir , 'posts' , 'posts-list.json' ) , 'utf-8' ) ) as Post [ ] ;
6724
68- const target = outputPath ( route ) ;
69- await mkdir ( dirname ( target ) , { recursive : true } ) ;
70- await writeFile ( target , html , 'utf-8' ) ;
71- }
25+ const staticRoutes : PrerenderRoute [ ] = STATIC_ROUTES . map ( ( path ) => ( { path, ...DEFAULT_META } ) ) ;
26+ const postRoutes : PrerenderRoute [ ] = list . map ( ( post ) => ( {
27+ path : `/posts/${ post . slug } ` ,
28+ title : post . title ,
29+ description : post . description || DEFAULT_META . description ,
30+ image : `${ BASE_URL } /og/${ post . slug } .png` ,
31+ } ) ) ;
7232
73- console . log ( `Pre-rendered ${ routeMeta . size } routes (head meta only)` ) ;
33+ return [ ... staticRoutes , ... postRoutes ] ;
7434}
7535
76- prerender ( ) . catch ( ( error ) => {
77- console . error ( error ) ;
78- process . exit ( 1 ) ;
79- } ) ;
36+ await prerender ( { clientDir, baseUrl : BASE_URL , routes : await routes ( ) } ) ;
0 commit comments