@donmccurdy
There is nothing your package can do that will reliably cause my web application to deploy multiple JavaScript files if I haven’t configured my build and/or deployment process to expect that…
Thanks for your patience – I’ve tried this with the mentioned three bundlers and I think I see what you’re saying now. While they all support dynamic imports the the complexity seems to stem from the inability to properly resolve the path of the current script in order to load a dynamically loaded file relative to it. Webpack uses script tags to load a dynamic chunk but that script is loaded relative to the root html page rather than the script that’s referencing it which can cause problems.
Here’s what I found when testing out the three bundlers and you can find the set ups here if you want to check it out:
Rollup
This “just works” if you you specify a directory to output to rather than a file and output to “cjs” or “module” format. If “iife” or “umd” are specified or you try to output to a single file then the --inlineDynamicImports
flag must be used. Rollup fails if it’s not used and informs the user in a command line warning.
Webpack
This almost just works except for the above mentioned relative chunk path problem. By default if the root html page tries to load the index js file like so: ./bundle/index.js
then the chunk loading will not work. In order to fix this you need to specify the output.publicPath
option to be ./bundle/
.
Parcel
This does just work. It properly loads the dynamic imports relative to the original script. Out of curiosity I dug into the source to see how they were resolving the current script path and it looks like they’re scraping the current stack trace get the current script path.
I’m not sure if there’s a reason that webpack isn’t using the stack trace method but it would definitely simplify things for the end user. At the least it could check if document.currentScript is supported first and fall back to the stack trace approach.
I’m not sure what you make of the rollup case but it seems like Webpack should be able to handle this correctly similar to parcel, right?
This won’t roundtrip correctly with TextEncoder, because arbitrary binary data doesn’t have a 1:1 mapping to utf-8 characters.
Well that’s disappointing. Using base64 I see a filesize of 431kb or around a 33% increase. Encoding to just a basic string I and skipping base64 I see a file size of 333kb or an increase of 3%. I’m not sure if there’s another reason to not do that, though. I suppose in that case we can’t rely on the browser to decode it asynchronously using a blob url.
fetch( 'https://unpkg.com/three/examples/js/libs/draco/draco_decoder.wasm' )
.then( res => res.arrayBuffer() )
.then( buffer => {
const ua = new Uint8Array( buffer );
let str = '';
for ( let i = 0, l = ua.length; i < l; i ++ ) str += String.fromCharCode( ua[ i ] );
saveData( new Blob( [ str ] ), 'raw-string.js' ); // 333kb
const b64 = btoa( str );
saveData( new Blob( [ b64 ] ), 'base64-string.js' ); // 431kb
} );