@@ -5,7 +5,8 @@ import { getOctokit } from "npm:@actions/github";
55
66// Polyfill for missing performance.markResourceTiming function in Deno
77if (
8- typeof performance !== "undefined" && ! ( performance as any ) . markResourceTiming
8+ typeof performance !== "undefined" &&
9+ ! ( performance as any ) . markResourceTiming
910) {
1011 ( performance as any ) . markResourceTiming = ( ) => { } ;
1112}
@@ -38,8 +39,7 @@ const wasmPackageJson = JSON.parse(
3839) ;
3940const LoroWasmVersion = ( wasmPackageJson as { version : string } ) . version ;
4041const MapPackageDir = path . resolve ( __dirname , "../../loro-wasm-map" ) ;
41- const WASM_SOURCEMAP_BASE =
42- `https://unpkg.com/loro-crdt-map@${ LoroWasmVersion } ` ;
42+ const WASM_SOURCEMAP_BASE = `https://unpkg.com/loro-crdt-map@${ LoroWasmVersion } ` ;
4343const EMBED_SCRIPT = path . resolve (
4444 __dirname ,
4545 "../../../scripts/embed-wasm-sourcemap.mjs" ,
@@ -144,7 +144,7 @@ async function build() {
144144
145145 const sizeReportMarker = "<!-- loro-wasm-size-report -->" ;
146146 const existingComment = comments . find ( ( comment ) =>
147- comment . body ?. includes ( sizeReportMarker )
147+ comment . body ?. includes ( sizeReportMarker ) ,
148148 ) ;
149149
150150 if ( existingComment ) {
@@ -184,20 +184,21 @@ async function cargoBuild() {
184184 profile ,
185185 ] ;
186186 console . log ( cmd . join ( " " ) ) ;
187- const env : Record < string , string > | undefined = profile === "release"
188- ? ( ( ) => {
189- const existing = Deno . env . get ( "RUSTFLAGS" ) ;
190- const next = [ "-C debuginfo=2" ] ;
191- if ( existing && existing . length > 0 ) {
192- next . unshift ( existing ) ;
193- }
194- return {
195- RUSTFLAGS : next . join ( " " ) ,
196- CARGO_PROFILE_RELEASE_DEBUG : "true" ,
197- CARGO_PROFILE_RELEASE_STRIP : "none" ,
198- } ;
199- } ) ( )
200- : undefined ;
187+ const env : Record < string , string > | undefined =
188+ profile === "release"
189+ ? ( ( ) => {
190+ const existing = Deno . env . get ( "RUSTFLAGS" ) ;
191+ const next = [ "-C debuginfo=2" ] ;
192+ if ( existing && existing . length > 0 ) {
193+ next . unshift ( existing ) ;
194+ }
195+ return {
196+ RUSTFLAGS : next . join ( " " ) ,
197+ CARGO_PROFILE_RELEASE_DEBUG : "true" ,
198+ CARGO_PROFILE_RELEASE_STRIP : "none" ,
199+ } ;
200+ } ) ( )
201+ : undefined ;
201202 const status = await Deno . run ( {
202203 cmd,
203204 cwd : LoroWasmDir ,
@@ -226,8 +227,7 @@ async function buildTarget(target: string) {
226227
227228 // TODO: polyfill FinalizationRegistry
228229 const bindgenTarget = target === "browser" ? "bundler" : target ;
229- const cmd =
230- `wasm-bindgen --keep-debug --weak-refs --target ${ bindgenTarget } --out-dir ${ target } ${ RawWasmPath } ` ;
230+ const cmd = `wasm-bindgen --keep-debug --weak-refs --target ${ bindgenTarget } --out-dir ${ target } ${ RawWasmPath } ` ;
231231 console . log ( ">" , cmd ) ;
232232 await Deno . run ( { cmd : cmd . split ( " " ) , cwd : LoroWasmDir } ) . status ( ) ;
233233 console . log ( ) ;
@@ -259,16 +259,68 @@ async function buildTarget(target: string) {
259259 }
260260 if ( target === "browser" ) {
261261 console . log ( "🔨 Patching browser target" ) ;
262- const patch = await Deno . readTextFile (
262+ const patchTemplate = await Deno . readTextFile (
263263 path . resolve ( __dirname , "./browser_patch.js" ) ,
264264 ) ;
265+ const wasmBg = await Deno . readTextFile (
266+ path . resolve ( targetDirPath , "loro_wasm_bg.js" ) ,
267+ ) ;
268+ const patch = renderBrowserPatch ( patchTemplate , wasmBg ) ;
265269 await Deno . writeTextFile (
266270 path . resolve ( targetDirPath , "loro_wasm.js" ) ,
267271 patch ,
268272 ) ;
269273 }
270274}
271275
276+ function renderBrowserPatch ( template : string , wasmBg : string ) : string {
277+ const names = extractExportNames ( wasmBg ) ;
278+ if ( ! names . includes ( "__wbg_set_wasm" ) ) {
279+ throw new Error ( "loro_wasm_bg.js does not export __wbg_set_wasm" ) ;
280+ }
281+
282+ const importNames = names . map ( ( name ) => ` ${ name } ,` ) . join ( "\n" ) ;
283+ const importObject = names . map ( ( name ) => ` ${ name } ,` ) . join ( "\n" ) ;
284+ const exportNames = names . map ( ( name ) => ` ${ name } ,` ) . join ( "\n" ) ;
285+
286+ return template
287+ . replace (
288+ "/* __LORO_BROWSER_PATCH_IMPORTS__ */" ,
289+ `import {\n${ importNames } \n} from "./loro_wasm_bg.js";` ,
290+ )
291+ . replace ( "/* __LORO_BROWSER_PATCH_IMPORT_OBJECT__ */" , importObject )
292+ . replace (
293+ "/* __LORO_BROWSER_PATCH_EXPORTS__ */" ,
294+ `export {\n${ exportNames } \n};` ,
295+ ) ;
296+ }
297+
298+ function extractExportNames ( source : string ) : string [ ] {
299+ const names = new Set < string > ( ) ;
300+ const declaration =
301+ / ^ e x p o r t \s + (?: a s y n c \s + ) ? (?: f u n c t i o n | c l a s s | c o n s t | l e t | v a r ) \s + ( [ A - Z a - z _ $ ] [ \w $ ] * ) / gm;
302+ let match : RegExpExecArray | null ;
303+
304+ while ( ( match = declaration . exec ( source ) ) != null ) {
305+ names . add ( match [ 1 ] ) ;
306+ }
307+
308+ const exportList = / ^ e x p o r t \s * \{ \s * ( [ ^ } ] + ) \s * \} / gm;
309+ while ( ( match = exportList . exec ( source ) ) != null ) {
310+ for ( const part of match [ 1 ] . split ( "," ) ) {
311+ const name = part
312+ . trim ( )
313+ . split ( / \s + a s \s + / )
314+ . pop ( ) ;
315+ if ( name != null && / ^ [ A - Z a - z _ $ ] [ \w $ ] * $ / . test ( name ) ) {
316+ names . add ( name ) ;
317+ }
318+ }
319+ }
320+
321+ return [ ...names ] . sort ( ) ;
322+ }
323+
272324async function stripReferenceTypesFeatureHint ( ) {
273325 // wasm-bindgen 0.2.100 uses the `target_features` custom section to choose
274326 // externref table glue. Safari 16.0-16.3 lacks WebAssembly reference-types,
@@ -306,11 +358,7 @@ async function postProcessWasm(targetDirPath: string, target: string) {
306358 ] ) ;
307359
308360 if ( profile === "release" ) {
309- await runWasmTools ( [
310- "strip-debug" ,
311- wasmPath ,
312- wasmPath ,
313- ] ) ;
361+ await runWasmTools ( [ "strip-debug" , wasmPath , wasmPath ] ) ;
314362 }
315363}
316364
0 commit comments