speice.io/2011/11/webpack-industrial-complex/index.html

32 lines
25 KiB
HTML
Raw Normal View History

<!doctype html><html lang=en dir=ltr class="blog-wrapper blog-post-page plugin-blog plugin-id-default" data-has-hydrated=false><meta charset=UTF-8><meta name=generator content="Docusaurus v3.6.1"><title data-rh=true>The webpack industrial complex | The Old Speice Guy</title><meta data-rh=true name=viewport content="width=device-width,initial-scale=1.0"><meta data-rh=true name=twitter:card content=summary_large_image><meta data-rh=true property=og:url content=https://speice.io/2011/11/webpack-industrial-complex><meta data-rh=true property=og:locale content=en><meta data-rh=true name=docusaurus_locale content=en><meta data-rh=true name=docusaurus_tag content=default><meta data-rh=true name=docsearch:language content=en><meta data-rh=true name=docsearch:docusaurus_tag content=default><meta data-rh=true property=og:title content="The webpack industrial complex | The Old Speice Guy"><meta data-rh=true name=description content='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).'><meta data-rh=true property=og:description content='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).'><meta data-rh=true property=og:type content=article><meta data-rh=true property=article:published_time content=2022-11-20T12:00:00.000Z><link data-rh=true rel=icon href=/img/favicon.ico><link data-rh=true rel=canonical href=https://speice.io/2011/11/webpack-industrial-complex><link data-rh=true rel=alternate href=https://speice.io/2011/11/webpack-industrial-complex hreflang=en><link data-rh=true rel=alternate href=https://speice.io/2011/11/webpack-industrial-complex hreflang=x-default><script data-rh=true type=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><link rel=alternate type=application/rss+xml href=/rss.xml title="The Old Speice Guy RSS Feed"><link rel=alternate type=application/atom+xml href=/atom.xml title="The Old Speice Guy Atom Feed"><link rel=stylesheet href=/katex/katex.min.css><link rel=stylesheet href=/assets/css/styles.16c3428d.css><script src=/assets/js/runtime~main.29a27dcf.js defer></script><script src=/assets/js/main.d461af80.js defer></script><body class=navigation-with-keyboard><script>!function(){var t,e=function(){try{return new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{return window.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>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id=starting-strong>Starting strong<a href=#starting-strong class=hash-link aria-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>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id=continuing-on>Continuing on<a href=#continuing-on class=hash-link aria-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 <a href=https://github.com/microsoft/TypeScript/issues/28308 target=_blank rel="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(&lt;local path>, import.meta.url)</code> and it worked! Well, kind of:</p>
<p><img decoding=async loading=lazy alt="Browser error" src=/assets/images/video_mp2t-1decc5fbd88b54dadd06691ce4c629ec.png width=1279 height=143 class=img_ev3q></p>
<p>That file has the audio processor code, so why does it get served with <code>Content-Type: video/mp2t</code>?</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id=floundering-about>Floundering about<a href=#floundering-about class=hash-link aria-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 <a href=https://hackernoon.com/implementing-audioworklets-with-react-8a80a470474 target=_blank rel="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 <a href=https://github.com/webpack/webpack/issues/11543#issuecomment-917673256 target=_blank rel="noopener noreferrer">new</a> <a href=https://github.com/popelenkow/worker-url target=_blank rel="noopener noreferrer">loaders</a>, setting <a href=https://github.com/webpack/webpack/discussions/14093#discussioncomment-1257149 target=_blank rel="noopener noreferrer">asset rules</a>, even <a href=https://github.com/webpack/webpack/issues/11543#issuecomment-826897590 target=_blank rel="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 <a href=https://github.com/vercel/next.js/issues/24907 target=_blank rel="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>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id=learning-and-reflecting>Learning and reflecting<a href=#learning-and-reflecting class=hash-link aria-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>
</ul>
<p>In the end, learning new systems is fun, but a focus on tools that "just work" can leave users out in the cold if they break down.</div></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Blog post page navigation"><a class="pagination-nav__link pagination-nav__link--prev" href=/2019/12/release-the-gil><div class=pagination-nav__sublabel>Older post</div><div class=pagination-nav__label>Release the GIL</div></a><a class="pagination-nav__link pagination-nav__link--next" href=/2024/11/playing-with-fire><div class=pagination-nav__sublabel>Newer post</div><div class=pagination-nav__label>Playing with fire: The fractal flame algorithm</div></a></nav></main><div class="col col--2"><div class="tableOfContents_bqdL thin-scrollbar"><ul class="table-of-contents table-of-contents__left-border"><li><a href=#starting-strong class="table-of-contents__link toc-highlight">Starting strong</a><li><a href=#continuing-on class="table-of-contents__link toc-highlight">Continuing on</a><li><a href=#floundering-about class="table-of-contents__link toc-highlight">Floundering about</a><li><a href=#learning-and-reflecting class="table-of-contents__link toc-highlight">Learning and reflecting</a></ul></div></div></div></div></div><footer class=footer><div class="container container-fluid"><div class="footer__bottom text--center"><div class=footer__copyright>Copyright © 2024 Bradlee Speice</div></div></div></footer></div>