"use strict";(self.webpackChunkspeice_io=self.webpackChunkspeice_io||[]).push([["5644"],{74092:function(e,t,n){n.r(t),n.d(t,{assets:function(){return l},contentTitle:function(){return r},default:function(){return u},frontMatter:function(){return s},metadata:function(){return i},toc:function(){return c}});var i=n(74729),a=n(85893),o=n(50065);let s={slug:"2011/11/webpack-industrial-complex",title:"The webpack industrial complex",date:new Date("2022-11-20T12:00:00.000Z"),authors:["bspeice"],tags:[]},r=void 0,l={authorsImageUrls:[void 0]},c=[{value:"Starting strong",id:"starting-strong",level:2},{value:"Continuing on",id:"continuing-on",level:2},{value:"Floundering about",id:"floundering-about",level:2},{value:"Learning and reflecting",id:"learning-and-reflecting",level:2}];function d(e){let t={a:"a",code:"code",h2:"h2",img:"img",li:"li",p:"p",ul:"ul",...(0,o.a)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.p,{children:'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).'}),"\n",(0,a.jsx)(t.p,{children:"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."}),"\n",(0,a.jsx)(t.h2,{id:"starting-strong",children:"Starting strong"}),"\n",(0,a.jsx)(t.p,{children:'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."'}),"\n",(0,a.jsxs)(t.p,{children:["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 ",(0,a.jsx)(t.code,{children:"onEvent"})," handler and a function easy."]}),"\n",(0,a.jsx)(t.p,{children:'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."'}),"\n",(0,a.jsx)(t.h2,{id:"continuing-on",children:"Continuing on"}),"\n",(0,a.jsx)(t.p,{children:'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?'}),"\n",(0,a.jsxs)(t.p,{children:["The first sign something was amiss came from the TypeScript compiler errors showing the audio worklet API ",(0,a.jsx)(t.a,{href:"https://github.com/microsoft/TypeScript/issues/28308",children:"was missing"}),". After searching out Github issues and (unsuccessfully) tweaking the ",(0,a.jsx)(t.code,{children:".tsconfig"})," settings, I settled on installing a package and moving on."]}),"\n",(0,a.jsxs)(t.p,{children:['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 ',(0,a.jsx)(t.code,{children:"new URL(, import.meta.url)"})," and it worked! Well, kind of:"]}),"\n",(0,a.jsx)(t.p,{children:(0,a.jsx)(t.img,{alt:"Browser error",src:n(44328).Z+"",width:"1279",height:"143"})}),"\n",(0,a.jsxs)(t.p,{children:["That file has the audio processor code, so why does it get served with ",(0,a.jsx)(t.code,{children:"Content-Type: video/mp2t"}),"?"]}),"\n",(0,a.jsx)(t.h2,{id:"floundering-about",children:"Floundering about"}),"\n",(0,a.jsxs)(t.p,{children:["Now comes the second mistake: even though I didn't understand the error, I ignored recommendations to ",(0,a.jsx)(t.a,{href:"https://hackernoon.com/implementing-audioworklets-with-react-8a80a470474",children:"just use JavaScript"})," and stuck by the original TypeScript requirement."]}),"\n",(0,a.jsx)(t.p,{children:"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."}),"\n",(0,a.jsxs)(t.p,{children:["I tried three different CRA tools - ",(0,a.jsx)(t.code,{children:"react-app-rewired"}),", ",(0,a.jsx)(t.code,{children:"craco"}),", ",(0,a.jsx)(t.code,{children:"customize-react-app"})," - 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."]}),"\n",(0,a.jsxs)(t.p,{children:["I tried changing the webpack configuration: using ",(0,a.jsx)(t.a,{href:"https://github.com/webpack/webpack/issues/11543#issuecomment-917673256",children:"new"})," ",(0,a.jsx)(t.a,{href:"https://github.com/popelenkow/worker-url",children:"loaders"}),", setting ",(0,a.jsx)(t.a,{href:"https://github.com/webpack/webpack/discussions/14093#discussioncomment-1257149",children:"asset rules"}),", even ",(0,a.jsx)(t.a,{href:"https://github.com/webpack/webpack/issues/11543#issuecomment-826897590",children:"changing how webpack detects worker resources"}),". 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."]}),"\n",(0,a.jsxs)(t.p,{children:["I tried so many application frameworks. Next.js looked like a good candidate, but added its own ",(0,a.jsx)(t.a,{href:"https://github.com/vercel/next.js/issues/24907",children:"bespoke webpack complexity"})," 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."]}),"\n",(0,a.jsx)(t.h2,{id:"learning-and-reflecting",children:"Learning and reflecting"}),"\n",(0,a.jsx)(t.p,{children:'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.'}),"\n",(0,a.jsx)(t.p,{children:"For myself:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsx)(t.li,{children:'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'}),"\n",(0,a.jsx)(t.li,{children:"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"}),"\n"]}),"\n",(0,a.jsx)(t.p,{children:"For the tools:"}),"\n",(0,a.jsxs)(t.ul,{children:["\n",(0,a.jsx)(t.li,{children:"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"}),"\n",(0,a.jsx)(t.li,{children:'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'}),"\n",(0,a.jsx)(t.li,{children:"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"}),"\n"]}),"\n",(0,a.jsx)(t.p,{children:'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.'})]})}function u(e={}){let{wrapper:t}={...(0,o.a)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(d,{...e})}):d(e)}},44328:function(e,t,n){n.d(t,{Z:function(){return i}});let i=n.p+"assets/images/video_mp2t-1decc5fbd88b54dadd06691ce4c629ec.png"},50065:function(e,t,n){n.d(t,{Z:function(){return r},a:function(){return s}});var i=n(67294);let a={},o=i.createContext(a);function s(e){let t=i.useContext(o);return i.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),i.createElement(o.Provider,{value:t},e.children)}},74729:function(e){e.exports=JSON.parse('{"permalink":"/2011/11/webpack-industrial-complex","source":"@site/blog/2022-11-20-webpack-industrial-complex/index.mdx","title":"The webpack industrial complex","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).","date":"2022-11-20T12:00:00.000Z","tags":[],"readingTime":4.51,"hasTruncateMarker":true,"authors":[{"name":"Bradlee Speice","socials":{"github":"https://github.com/bspeice"},"key":"bspeice","page":null}],"frontMatter":{"slug":"2011/11/webpack-industrial-complex","title":"The webpack industrial complex","date":"2022-11-20T12:00:00.000Z","authors":["bspeice"],"tags":[]},"unlisted":false,"lastUpdatedAt":1731274898000,"prevItem":{"title":"Playing with fire: The fractal flame algorithm","permalink":"/2024/11/playing-with-fire"},"nextItem":{"title":"Release the GIL","permalink":"/2019/12/release-the-gil"}}')}}]);