[{"data":1,"prerenderedAt":591},["ShallowReactive",2],{"navigation":3,"\u002Fblog\u002Fdebugging-local-packages-with-pnpm-link":204,"\u002Fblog\u002Fdebugging-local-packages-with-pnpm-link-surround":586},[4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180,184,188,192,196,200],{"title":5,"path":6,"stem":7},"You do not have time to not have tests","\u002Fblog\u002Fyou-do-not-have-time-to-not-have-tests","2.blog\u002F20211217.you-do-not-have-time-to-not-have-tests",{"title":9,"path":10,"stem":11},"Migrate Vue 2 with Vuetify and Jest to Vite and Vitest","\u002Fblog\u002Fmigrate-vue-2-with-vuetify-and-jest-to-vite-and-vitest","2.blog\u002F20220109.migrate-vue-2-with-vuetify-and-jest-to-vite-and-vitest",{"title":13,"path":14,"stem":15},"I am a Dark Matter Developer","\u002Fblog\u002Fi-am-a-dark-matter-developer","2.blog\u002F20220626.i-am-a-dark-matter-developer",{"title":17,"path":18,"stem":19},"Why using Conventional commits is useful","\u002Fblog\u002Fusing-conventional-commits","2.blog\u002F20240623.using-conventional-commits",{"title":21,"path":22,"stem":23},"Why you should make a toolbox repository","\u002Fblog\u002Fwhy-you-should-make-a-toolbox-repository","2.blog\u002F20240630.Why-you-should-make-a-toolbox-repository",{"title":25,"path":26,"stem":27},"Apache Airflow Part 1 - Why and Goals for a near Serverless ELT","\u002Fblog\u002Fapache-airflow-part-1-why-and-goals","2.blog\u002F20240710.apache-airflow-part-1-why-and-goals",{"title":29,"path":30,"stem":31},"Oh My Zsh on your server","\u002Fblog\u002Foh-my-zsh-on-your-server","2.blog\u002F20240711.oh-my-zsh-on-your-server",{"title":33,"path":34,"stem":35},"Fire tablet and YouTube Kids","\u002Fblog\u002Ffire-tablet-and-youtube-kids","2.blog\u002F20240714.fire-tablet-and-youtube-kids",{"title":37,"path":38,"stem":39},"Using Ollama and Continue as a GitHub Copilot Alternative","\u002Fblog\u002Fusing-ollama-and-continue-as-github-copilot-alternative","2.blog\u002F20240723.using-ollama-and-continue-as-github-copilot-alternative",{"title":41,"path":42,"stem":43},"Debugging Local Packages Made Easy with pnpm","\u002Fblog\u002Fdebugging-local-packages-with-pnpm-link","2.blog\u002F20250422.debugging local-packages-with-pnpm-link",{"title":45,"path":46,"stem":47},"Two Weeks with Cloudflare AI and Tools","\u002Fblog\u002Ftwo-weeks-with-cloudflare-ai-and-tools","2.blog\u002F20250509.two-weeks-with-cloudflare-aI-and-tools",{"title":49,"path":50,"stem":51},"Adding Prompts to VS Code - How I Learned to Stop Worrying and Love AI Context","\u002Fblog\u002Fadding-prompts-to-vscode","2.blog\u002F20250528.adding-prompts-to-vscode",{"title":53,"path":54,"stem":55},"My Best Practices","\u002Fblog\u002Fmy-best-practicies","2.blog\u002F20250607.my-best-practicies",{"title":57,"path":58,"stem":59},"Creating my own CLI Tool - Towles Tool","\u002Fblog\u002Ftowles-tool","2.blog\u002F20250607.towles-tool",{"title":61,"path":62,"stem":63},"Software Development Best Practices & ITIL","\u002Fblog\u002Fsoftware-engineering-and-itil-best-practices","2.blog\u002F20250612.software-engineering-and-itil-best-practices",{"title":65,"path":66,"stem":67},"Voice to Text","\u002Fblog\u002Fvoice-to-text","2.blog\u002F20250622.voice-to-text",{"title":69,"path":70,"stem":71},"Setting Up ComfyUI - A Better Alternative to Fooocus","\u002Fblog\u002Fcomfy-ui-setup","2.blog\u002F20250628.comfy-ui-setup",{"title":73,"path":74,"stem":75},"Voice to System","\u002Fblog\u002Fvoice-to-system","2.blog\u002F20250705.voice-to-system",{"title":77,"path":78,"stem":79},"Tips for Claude Code","\u002Fblog\u002Ftips-for-claude-code","2.blog\u002F20250713.tips-for-claude-code",{"title":81,"path":82,"stem":83},"Review That AI Code: Why I Read Every Line Generated Code","\u002Fblog\u002Freview-that-ai-code","2.blog\u002F20250720.review-that-ai-code",{"title":85,"path":86,"stem":87},"My Context Engineering Journey: From Dev Scripts to AI Collaboration","\u002Fblog\u002F20250803-1.my-context-engineering-journey","2.blog\u002F20250803-1.my-context-engineering-journey",{"title":89,"path":90,"stem":91},"Context Engineering at Scale: Enterprise Lessons and the Future of Development","\u002Fblog\u002F20250803-2.context-engineering-at-scale","2.blog\u002F20250803-2.context-engineering-at-scale",{"title":93,"path":94,"stem":95},"Check That Your Tools and Linters Do Not Burn Tokens","\u002Fblog\u002Fcheck-that-your-tools-and-linters-do-not-burn-tokens","2.blog\u002F20250806.check-that-your-tools-and-linters-do-not-burn-tokens",{"title":97,"path":98,"stem":99},"Markdown + AI: The Communication Protocol That Changes Everything","\u002Fblog\u002Fmarkdown-plus-ai-the-communication-protocol-that-changes-everything","2.blog\u002F20250814.markdown-plus-ai-the-communication-protocol-that-changes-everything",{"title":101,"path":102,"stem":103},"Finally: Type-Safe AI in Production (And Why I'm Here For It)","\u002Fblog\u002Ffinally-type-safe-ai-in-production-and-why-im-here-for-it","2.blog\u002F20250819.finally-type-safe-ai-in-production-and-why-im-here-for-it",{"title":105,"path":106,"stem":107},"Dotfiles: Masterpiece or Late Stage Picasso?","\u002Fblog\u002Fdotfiles-masterpiece-or-late-stage-picasso","2.blog\u002F20250822.dotfiles-masterpiece-or-late-stage-picasso",{"title":109,"path":110,"stem":111},"Beyond API Wrappers: Building State-Driven MCP Servers for Long-Horizon Agent Orchestration","\u002Fblog\u002Fbeyond-api-wrappers-mcp-servers","2.blog\u002F20250907.beyond-api-wrappers-mcp-servers",{"title":113,"path":114,"stem":115},"Why Vertical Integration Wins: A Software Engineer's Case for Owning Your Stack","\u002Fblog\u002Fwhy-i-bought-tesla-model-3-vertical-integration","2.blog\u002F20250928.why-i-bought-tesla-model-3-vertical-integration",{"title":117,"path":118,"stem":119},"The Min-Maxer's Trifecta: Building Tools for the Game You Actually Play","\u002Fblog\u002Fmin-maxer-trifecta","2.blog\u002F20251004.min-maxer-trifecta",{"title":121,"path":122,"stem":123},"Read The Source: Learning by Cutting Out The Middleman and RTFM","\u002Fblog\u002Fread-the-source","2.blog\u002F20251010.read-the-source",{"title":125,"path":126,"stem":127},"The Exponential Shift: Why AI Progress Feels Different Now","\u002Fblog\u002Fthe-exponential-shift","2.blog\u002F20251015.the-exponential-shift",{"title":129,"path":130,"stem":131},"Plan Mode for Your Problems, Edit Mode for Claude's","\u002Fblog\u002Fplan-mode-problems-edit-mode-solutions","2.blog\u002F20251019.plan-mode-problems-edit-mode-solutions",{"title":133,"path":134,"stem":135},"AWS Aurora DSQL Looked Perfect Until I Needed the Connection String","\u002Fblog\u002Faws-aurora-dsql-postgres-serverless-authentication","2.blog\u002F20251028.aws-aurora-dsql-postgres-serverless-authentication",{"title":137,"path":138,"stem":139},"Switchback: Browser History for Your Thoughts","\u002Fblog\u002Fswitchback-second-order-reasoning","2.blog\u002F20251205.switchback-second-order-reasoning",{"title":141,"path":142,"stem":143},"AI Pairing: Notes to Self","\u002Fblog\u002Fai-pairing-notes-to-self","2.blog\u002F20251216.ai-pairing-notes-to-self",{"title":145,"path":146,"stem":147},"I've Been Sleeping on Zellij","\u002Fblog\u002Fsleeping-on-zellij","2.blog\u002F20251229.sleeping-on-zellij",{"title":149,"path":150,"stem":151},"Implementing a Ralph Wiggum Loop: The Secret is Session Markers","\u002Fblog\u002Fimplementing-ralph-wiggum-loop-for-autonomous-ai-coding","2.blog\u002F20260114.implementing-ralph-wiggum-loop-for-autonomous-ai-coding",{"title":153,"path":154,"stem":155},"Goodhart's Law Ate My Context Window","\u002Fblog\u002Fgoodharts-law-ate-my-context-window","2.blog\u002F20260119.goodharts-law-ate-my-context-window",{"title":157,"path":158,"stem":159},"Claude Code's Hidden Multi-Agent System Is Real","\u002Fblog\u002Fclaude-code-hidden-multi-agent-system","2.blog\u002F20260124.claude-code-hidden-multi-agent-system",{"title":161,"path":162,"stem":163},"Free Printable Math Sheets for Kids — Number Chart, Skip Counting, Multiplication, and More","\u002Fblog\u002Ffree-printable-number-chart-and-coin-sheets","2.blog\u002F20260214.free-printable-number-chart-and-coin-sheets",{"title":165,"path":166,"stem":167},"We Are Near the End of the Exponential","\u002Fblog\u002Fnear-the-end-of-the-exponential","2.blog\u002F20260214.near-the-end-of-the-exponential",{"title":169,"path":170,"stem":171},"Free Printable Language Arts Sheets for Kids — Sight Words, Parts of Speech, Homophones, and More","\u002Fblog\u002Ffree-printable-sight-words-and-grammar-sheets","2.blog\u002F20260215.free-printable-sight-words-and-grammar-sheets",{"title":173,"path":174,"stem":175},"Interactive Code Execution with Artifacts","\u002Fblog\u002Finteractive-code-execution-with-artifacts","2.blog\u002F20260215.interactive-code-execution-with-artifacts",{"title":177,"path":178,"stem":179},"Free Printable Telling Time Worksheet for Kids — Clock Reference & Practice Sheet","\u002Fblog\u002Ffree-printable-telling-time-worksheet","2.blog\u002F20260216.free-printable-telling-time-worksheet",{"title":181,"path":182,"stem":183},"Claude Code Skills: Teaching AI Your Playbook","\u002Fblog\u002Fclaude-code-skills-guide","2.blog\u002F20260221.claude-code-skills-guide",{"title":185,"path":186,"stem":187},"Building a Multi-Agent Loan Approval System with Human-in-the-Loop","\u002Fblog\u002Fmulti-agent-loan-approval-human-in-the-loop","2.blog\u002F20260225.multi-agent-loan-approval-human-in-the-loop",{"title":189,"path":190,"stem":191},"The Inception of AI Infrastructure: Bottlenecks All the Way Down","\u002Fblog\u002Fbiggest-bottleneck-scaling-ai-compute","2.blog\u002F20260313.biggest-bottleneck-scaling-ai-compute",{"title":193,"path":194,"stem":195},"What I Tell Teams About Claude Code","\u002Fblog\u002Fwhat-i-tell-teams-about-claude-code","2.blog\u002F20260314.what-i-tell-teams-about-claude-code",{"title":197,"path":198,"stem":199},"The Hardest Part of AI Isn't the AI","\u002Fblog\u002Fthe-hardest-part-of-ai-isnt-the-ai","2.blog\u002F20260327.the-hardest-part-of-ai-isnt-the-ai",{"title":201,"path":202,"stem":203},"Claude Code Hooks: The Capability I Left on the Table","\u002Fblog\u002Fclaude-code-hooks-capability-left-on-the-table","2.blog\u002F20260401.claude-code-hooks-capability-left-on-the-table",{"id":205,"title":41,"authors":206,"badge":212,"body":214,"date":575,"description":576,"extension":577,"image":578,"meta":581,"navigation":582,"path":42,"seo":583,"status":584,"stem":43,"__hash__":585},"posts\u002F2.blog\u002F20250422.debugging local-packages-with-pnpm-link.md",[207],{"name":208,"to":209,"avatar":210},"Chris Towles","https:\u002F\u002Ftwitter.com\u002FChris_Towles",{"src":211},"\u002Fimages\u002Fctowles-profile-512x512.png",{"label":213},"Node.js",{"type":215,"value":216,"toc":568},"minimark",[217,226,230,235,240,243,260,270,277,390,399,403,470,474,489,493,496,547,551,564],[218,219,221,222],"h1",{"id":220},"debugging-local-packages-with-pnpm-link","Debugging Local Packages with ",[223,224,225],"code",{},"pnpm link",[227,228,229],"p",{},"If you’re tired of copy-pasting your local library into your app or publishing endless pre-release versions just to test a small change, there’s a better way.",[227,231,232,234],{},[223,233,225],{}," lets you connect your local package to your app, so you can debug and test changes without extra hassle.",[236,237,239],"h2",{"id":238},"meet-the-cast","Meet the Cast",[227,241,242],{},"Picture this:",[244,245,246,254],"ul",{},[247,248,249,253],"li",{},[250,251,252],"strong",{},"cool-package\u002F",": An open-source package you're working to contribute to because you're trying to fix a bug.",[247,255,256,259],{},[250,257,258],{},"my-app\u002F",": The app that uses that package.",[261,262,267],"pre",{"className":263,"code":265,"language":266},[264],"language-text","cool-package\u002F\n├── src\u002F\n│   └── index.js\n└── package.json\n\nmy-app\u002F\n├── src\u002F\n│   └── main.js\n└── package.json\n","text",[223,268,265],{"__ignoreMap":269},"",[227,271,272,273,276],{},"Your ",[223,274,275],{},"my-app\u002Fpackage.json"," might look like this:",[261,278,282],{"className":279,"code":280,"language":281,"meta":269,"style":269},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"name\": \"my-app\",\n  \"version\": \"1.0.0\",\n  \"dependencies\": {\n    \"@cool\u002Fpackage\": \"1.0.0\"\n  }\n}\n","json",[223,283,284,293,321,342,357,378,384],{"__ignoreMap":269},[285,286,289],"span",{"class":287,"line":288},"line",1,[285,290,292],{"class":291},"sMK4o","{\n",[285,294,296,299,303,306,309,312,316,318],{"class":287,"line":295},2,[285,297,298],{"class":291},"  \"",[285,300,302],{"class":301},"spNyl","name",[285,304,305],{"class":291},"\"",[285,307,308],{"class":291},":",[285,310,311],{"class":291}," \"",[285,313,315],{"class":314},"sfazB","my-app",[285,317,305],{"class":291},[285,319,320],{"class":291},",\n",[285,322,324,326,329,331,333,335,338,340],{"class":287,"line":323},3,[285,325,298],{"class":291},[285,327,328],{"class":301},"version",[285,330,305],{"class":291},[285,332,308],{"class":291},[285,334,311],{"class":291},[285,336,337],{"class":314},"1.0.0",[285,339,305],{"class":291},[285,341,320],{"class":291},[285,343,345,347,350,352,354],{"class":287,"line":344},4,[285,346,298],{"class":291},[285,348,349],{"class":301},"dependencies",[285,351,305],{"class":291},[285,353,308],{"class":291},[285,355,356],{"class":291}," {\n",[285,358,360,363,367,369,371,373,375],{"class":287,"line":359},5,[285,361,362],{"class":291},"    \"",[285,364,366],{"class":365},"sBMFI","@cool\u002Fpackage",[285,368,305],{"class":291},[285,370,308],{"class":291},[285,372,311],{"class":291},[285,374,337],{"class":314},[285,376,377],{"class":291},"\"\n",[285,379,381],{"class":287,"line":380},6,[285,382,383],{"class":291},"  }\n",[285,385,387],{"class":287,"line":386},7,[285,388,389],{"class":291},"}\n",[227,391,392,393,395,396,398],{},"But you want to test changes in ",[223,394,366],{}," without publishing it every time. Here’s how to use ",[223,397,225],{},".",[236,400,402],{"id":401},"the-two-step-process","The Two-Step Process",[404,405,406,438],"ol",{},[247,407,408,308,411],{},[250,409,410],{},"Link the package globally",[261,412,416],{"className":413,"code":414,"language":415,"meta":269,"style":269},"language-zsh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","cd @cool\u002Fpackage\npnpm link --global\n","zsh",[223,417,418,427],{"__ignoreMap":269},[285,419,420,424],{"class":287,"line":288},[285,421,423],{"class":422},"s2Zo4","cd",[285,425,426],{"class":314}," @cool\u002Fpackage\n",[285,428,429,432,435],{"class":287,"line":295},[285,430,431],{"class":365},"pnpm",[285,433,434],{"class":314}," link",[285,436,437],{"class":314}," --global\n",[247,439,440,308,443,466,469],{},[250,441,442],{},"Link it into your app",[261,444,446],{"className":413,"code":445,"language":415,"meta":269,"style":269},"cd ..\u002Fmy-app\npnpm link --global @cool\u002Fpackage\n",[223,447,448,455],{"__ignoreMap":269},[285,449,450,452],{"class":287,"line":288},[285,451,423],{"class":422},[285,453,454],{"class":314}," ..\u002Fmy-app\n",[285,456,457,459,461,464],{"class":287,"line":295},[285,458,431],{"class":365},[285,460,434],{"class":314},[285,462,463],{"class":314}," --global",[285,465,426],{"class":314},[467,468],"br",{},"Now, your app uses your local version.",[236,471,473],{"id":472},"debugging","Debugging",[244,475,476,481,486],{},[247,477,478,479,398],{},"Edit code in ",[223,480,366],{},[247,482,483,484,398],{},"Run or debug ",[223,485,315],{},[247,487,488],{},"If you need to build your library, run your build command.",[236,490,492],{"id":491},"unlink-when-youre-done","Unlink When You’re Done",[227,494,495],{},"To go back to the registry version:",[404,497,498,530],{},[247,499,500,501,503,504],{},"In ",[223,502,315],{},":\n",[261,505,507],{"className":413,"code":506,"language":415,"meta":269,"style":269},"pnpm unlink --global @cool\u002Fpackage\npnpm install --force\n",[223,508,509,520],{"__ignoreMap":269},[285,510,511,513,516,518],{"class":287,"line":288},[285,512,431],{"class":365},[285,514,515],{"class":314}," unlink",[285,517,463],{"class":314},[285,519,426],{"class":314},[285,521,522,524,527],{"class":287,"line":295},[285,523,431],{"class":365},[285,525,526],{"class":314}," install",[285,528,529],{"class":314}," --force\n",[247,531,500,532,503,534],{},[223,533,366],{},[261,535,537],{"className":413,"code":536,"language":415,"meta":269,"style":269},"pnpm unlink --global\n",[223,538,539],{"__ignoreMap":269},[285,540,541,543,545],{"class":287,"line":288},[285,542,431],{"class":365},[285,544,515],{"class":314},[285,546,437],{"class":314},[236,548,550],{"id":549},"summary","Summary",[227,552,553,555,556,563],{},[223,554,225],{}," is a useful tool for local package development. It makes stepping into the code with breakpoints and debugging a breeze. See the ",[557,558,562],"a",{"href":559,"rel":560},"https:\u002F\u002Fpnpm.io\u002Fcli\u002Flink",[561],"nofollow","PNPM docs on link"," for more details.",[565,566,567],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}",{"title":269,"searchDepth":295,"depth":295,"links":569},[570,571,572,573,574],{"id":238,"depth":295,"text":239},{"id":401,"depth":295,"text":402},{"id":472,"depth":295,"text":473},{"id":491,"depth":295,"text":492},{"id":549,"depth":295,"text":550},"2025-04-22","Debug your local Node.js packages like a pro (and with less pain) using pnpm link.","md",{"src":579,"alt":580},"\u002Fimages\u002Fblog\u002Fdeveloper-debugging-code.png","A Developer looking at a monitor trying to debug code",{},true,{"title":41,"description":576},"published","aqyJQlXXiPsXUuXG9DQqQXxI2C0XCJsFmv9-4ohrbLY",[587,589],{"title":37,"path":38,"stem":39,"description":588,"status":584,"children":-1},"A guide on how Ollama and Continue can serve as an alternative to GitHub Copilot.",{"title":45,"path":46,"stem":47,"description":590,"status":584,"children":-1},"My Odyssey (and Why I Switched to AWS Bedrock)",1776221196452]