1
+ import { existsSync } from "node:fs" ;
1
2
import { readFile } from "node:fs/promises" ;
2
- import { resolve } from "node:path" ;
3
+ import { dirname , join , resolve } from "node:path" ;
3
4
import { fileURLToPath } from "node:url" ;
4
5
import type { TemplateLiteral } from "acorn" ;
5
6
import { JSDOM } from "jsdom" ;
@@ -42,7 +43,7 @@ export function observable({
42
43
} ,
43
44
transformIndexHtml : {
44
45
order : "pre" ,
45
- async handler ( input ) {
46
+ async handler ( input , context ) {
46
47
const notebook = deserialize ( input , { parser} ) ;
47
48
const tsource = await readFile ( template , "utf-8" ) ;
48
49
const document = parser . parseFromString ( tsource , "text/html" ) ;
@@ -89,6 +90,9 @@ export function observable({
89
90
}
90
91
}
91
92
93
+ // Don’t error if assets are missing (matching Vite’s behavior).
94
+ filterMissingAssets ( assets , dirname ( context . filename ) ) ;
95
+
92
96
const output = serializer . serializeToString ( document ) ;
93
97
const i = output . indexOf ( "</body>" ) ;
94
98
if ( ! ( i >= 0 ) ) throw new Error ( "body not found" ) ;
@@ -103,16 +107,16 @@ import {define} from "observable:runtime/define";${Array.from(assets)
103
107
import asset${ i + 1 } from ${ JSON . stringify ( `${ asset } ?url` ) } ;`
104
108
)
105
109
. join ( "" ) } ${
106
- assets . size > 0
107
- ? `
110
+ assets . size > 0
111
+ ? `
108
112
109
113
const assets = new Map([
110
114
${ Array . from ( assets )
111
115
. map ( ( asset , i ) => ` [${ JSON . stringify ( asset ) } , asset${ i + 1 } ]` )
112
116
. join ( ",\n" ) }
113
117
]);`
114
- : ""
115
- }
118
+ : ""
119
+ }
116
120
${ notebook . cells
117
121
. filter ( ( cell ) => ! statics . has ( cell ) )
118
122
. map ( ( cell ) => {
@@ -146,11 +150,20 @@ define(
146
150
} ;
147
151
}
148
152
153
+ function filterMissingAssets ( assets : Set < string > , dir : string ) : void {
154
+ for ( const asset of assets ) {
155
+ if ( ! existsSync ( join ( dir , asset ) ) ) {
156
+ console . warn ( `warning: asset not found: ${ asset } ` ) ;
157
+ assets . delete ( asset ) ;
158
+ }
159
+ }
160
+ }
161
+
149
162
function stripExpressions ( template : TemplateLiteral , input : string ) : string {
150
163
const source = new Sourcemap ( input ) ;
151
164
let index = template . start ;
152
165
for ( const q of template . quasis ) {
153
- if ( q . start > index ) source . replaceLeft ( index , q . start , "…" ) ;
166
+ if ( q . start > index ) source . delete ( index , q . start ) ;
154
167
index = q . end ;
155
168
}
156
169
return String ( source ) ;
0 commit comments