<!doctype html><htmllang=endir=ltrclass="blog-wrapper blog-post-page plugin-blog plugin-id-default"data-has-hydrated=false><metacharset=UTF-8><metaname=generatorcontent="Docusaurus v3.6.1"><titledata-rh=true>The webpack industrial complex | The Old Speice Guy</title><metadata-rh=truename=viewportcontent="width=device-width,initial-scale=1.0"><metadata-rh=truename=twitter:cardcontent=summary_large_image><metadata-rh=trueproperty=og:urlcontent=https://speice.io/2011/11/webpack-industrial-complex><metadata-rh=trueproperty=og:localecontent=en><metadata-rh=truename=docusaurus_localecontent=en><metadata-rh=truename=docusaurus_tagcontent=default><metadata-rh=truename=docsearch:languagecontent=en><metadata-rh=truename=docsearch:docusaurus_tagcontent=default><metadata-rh=trueproperty=og:titlecontent="The webpack industrial complex | The Old Speice Guy"><metadata-rh=truename=descriptioncontent='This started because I wanted to build a synthesizer. Setting a goal of "digital DX7" was ambitious, but I needed something unrelated to the day job. Beyond that, working with audio seemed like a good challenge. I enjoy performance-focused code, and performance problems in audio are conspicuous. Building a web project was an obvious choice because of the web audio API documentation and independence from a large Digital Audio Workstation (DAW).'><metadata-rh=trueproperty=og:descriptioncontent='This started because I wanted to build a synthesizer. Setting a goal of "digital DX7" was ambitious, but I needed something unrelated to the day job. Beyond that, working with audio seemed like a good challenge. I enjoy performance-focused code, and performance problems in audio are conspicuous. Building a web project was an obvious choice because of the web audio API documentation and independence from a large Digital Audio Workstation (DAW).'><metadata-rh=trueproperty=og:typecontent=article><metadata-rh=trueproperty=article:published_timecontent=2022-11-20T12:00:00.000Z><linkdata-rh=truerel=iconhref=/img/favicon.ico><linkdata-rh=truerel=canonicalhref=https://speice.io/2011/11/webpack-industrial-complex><linkdata-rh=truerel=alternatehref=https://speice.io/2011/11/webpack-industrial-complexhreflang=en><linkdata-rh=truerel=alternatehref=https://speice.io/2011/11/webpack-industrial-complexhreflang=x-default><scriptdata-rh=truetype=application/ld+json>{"@context":"https://schema.org","@id":"https://speice.io/2011/11/webpack-industrial-complex","@type":"BlogPosting","author":{"@type":"Person","name":"Bradlee Speice"},"dateModified":"2024-11-10T21:41:38.000Z","datePublished":"2022-11-20T12:00:00.000Z","description":"This started because I wanted to build a synthesizer. Setting a goal of \"digital DX7\" was ambitious, but I needed something unrelated to the day job. Beyond that, working with audio seemed like a good challenge. I enjoy performance-focused code, and performance problems in audio are conspicuous. Building a web project was an obvious choice because of the web audio API documentation and independence from a large Digital Audio Workstation (DAW).","headline":"The webpack industrial complex","isPartOf":{"@id":"https://speice.io/","@type":"Blog","name":"Blog"},"keywords":[],"mainEntityOfPage":"https://speice.io/2011/11/webpack-industrial-complex","name":"The webpack industrial complex","url":"https://speice.io/2011/11/webpack-industrial-complex"}</script><linkrel=alternatetype=application/rss+xmlhref=/rss.xmltitle="The Old Speice Guy RSS Feed"><linkrel=alternatetype=application/atom+xmlhref=/atom.xmltitle="The Old Speice Guy Atom Feed"><linkrel=stylesheethref=/katex/katex.min.css><linkrel=stylesheethref=/assets/css/styles.16c3428d.css><scriptsrc=/assets/js/runtime~main.29a27dcf.jsdefer></script><scriptsrc=/assets/js/main.d461af80.jsdefer></script><bodyclass=navigation-with-keyboard><script>!function(){vart,e=function(){try{returnnewURLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{returnwindow.localStorage.getItem("theme"
<p>The project was soon derailed trying to sort out technical issues unrelated to the original purpose. Finding a resolution was a frustrating journey, and it's still not clear whether those problems were my fault. As a result, I'm writing this to try making sense of it, as a case study/reference material, and to salvage something from the process.</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id=starting-strong>Starting strong<ahref=#starting-strongclass=hash-linkaria-label="Direct link to Starting strong"title="Direct link to Starting strong"></a></h2>
<p>The sole starting requirement was to write everything in TypeScript. Not because of project scale, but because guardrails help with unfamiliar territory. Keeping that in mind, the first question was: how does one start a new project? All I actually need is "compile TypeScript, show it in a browser."</p>
<p>Create React App (CRA) came to the rescue and the rest of that evening was a joy. My TypeScript/JavaScript skills were rusty, but the online documentation was helpful. I had never understood the appeal of JSX (why put a DOM in JavaScript?) until it made connecting an <code>onEvent</code> handler and a function easy.</p>
<p>Some quick dimensional analysis later and there was a sine wave oscillator playing A=440 through the speakers. I specifically remember thinking "modern browsers are magical."</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id=continuing-on>Continuing on<ahref=#continuing-onclass=hash-linkaria-label="Direct link to Continuing on"title="Direct link to Continuing on"></a></h2>
<p>Now comes the first mistake: I began to worry about "scale" before encountering an actual problem. Rather than rendering audio in the main thread, why not use audio worklets and render in a background thread instead?</p>
<p>The first sign something was amiss came from the TypeScript compiler errors showing the audio worklet API <ahref=https://github.com/microsoft/TypeScript/issues/28308target=_blankrel="noopener noreferrer">was missing</a>. After searching out Github issues and (unsuccessfully) tweaking the <code>.tsconfig</code> settings, I settled on installing a package and moving on.</p>
<p>The next problem came from actually using the API. Worklets must load from separate "modules," but it wasn't clear how to guarantee the worklet code stayed separate from the application. I saw recommendations to use <code>new URL(<local path>, import.meta.url)</code> and it worked! Well, kind of:</p>
<p>That file has the audio processor code, so why does it get served with <code>Content-Type: video/mp2t</code>?</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id=floundering-about>Floundering about<ahref=#floundering-aboutclass=hash-linkaria-label="Direct link to Floundering about"title="Direct link to Floundering about"></a></h2>
<p>Now comes the second mistake: even though I didn't understand the error, I ignored recommendations to <ahref=https://hackernoon.com/implementing-audioworklets-with-react-8a80a470474target=_blankrel="noopener noreferrer">just use JavaScript</a> and stuck by the original TypeScript requirement.</p>
<p>I tried different project structures. Moving the worklet code to a new folder didn't help, nor did setting up a monorepo and placing it in a new package.</p>
<p>I tried three different CRA tools - <code>react-app-rewired</code>, <code>craco</code>, <code>customize-react-app</code> - but got the same problem. Each has varying levels of compatibility with recent CRA versions, so it wasn't clear if I had the right solution but implemented it incorrectly. After attempting to eject the application and panicking after seeing the configuration, I abandoned that as well.</p>
<p>I tried changing the webpack configuration: using <ahref=https://github.com/webpack/webpack/issues/11543#issuecomment-917673256target=_blankrel="noopener noreferrer">new</a><ahref=https://github.com/popelenkow/worker-urltarget=_blankrel="noopener noreferrer">loaders</a>, setting <ahref=https://github.com/webpack/webpack/discussions/14093#discussioncomment-1257149target=_blankrel="noopener noreferrer">asset rules</a>, even <ahref=https://github.com/webpack/webpack/issues/11543#issuecomment-826897590target=_blankrel="noopener noreferrer">changing how webpack detects worker resources</a>. In hindsight, entry points may have been the answer. But because CRA actively resists attempts to change its webpack configuration, and I couldn't find audio worklet examples in any other framework, I gave up.</p>
<p>I tried so many application frameworks. Next.js looked like a good candidate, but added its own <ahref=https://github.com/vercel/next.js/issues/24907target=_blankrel="noopener noreferrer">bespoke webpack complexity</a> to the existing confusion. Astro had the best "getting started" experience, but I refuse to install an IDE-specific plugin. I first used Deno while exploring Lume, but it couldn't import the audio worklet types (maybe because of module compatibility?). Each framework was unique in its own way (shout-out to SvelteKit) but I couldn't figure out how to make them work.</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id=learning-and-reflecting>Learning and reflecting<ahref=#learning-and-reflectingclass=hash-linkaria-label="Direct link to Learning and reflecting"title="Direct link to Learning and reflecting"></a></h2>
<p>I ended up using Vite and vite-plugin-react-pages to handle both "build the app" and "bundle worklets," but the specific tool choice isn't important. Instead, the focus should be on lessons learned.</p>
<p>For myself:</p>
<ul>
<li>I'm obsessed with tooling, to the point it can derail the original goal. While it comes from a good place (for example: "types are awesome"), it can get in the way of more important work</li>
<li>I tend to reach for online resources right after seeing a new problem. While finding help online is often faster, spending time understanding the problem would have been more productive than cycling through (often outdated) blog posts</li>
</ul>
<p>For the tools:</p>
<ul>
<li>Resource bundling is great and solves a genuine challenge. I've heard too many horror stories of developers writing modules by hand to believe this is unnecessary complexity</li>
<li>Webpack is a build system and modern frameworks are deeply dependent on it (hence the "webpack industrial complex"). While this often saves users from unnecessary complexity, there's no path forward if something breaks</li>
<li>There's little ability to mix and match tools across frameworks. Next.js and Gatsby let users extend webpack, but because each framework adds its own modules, changes aren't portable. After spending a week looking at webpack, I had an example running with parcel in thirty minutes, but couldn't integrate it</li>