<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Rules_js on Johannes' blog</title><link>https://nerden.de/tags/rules_js/</link><description>Recent content in Rules_js on Johannes' blog</description><generator>Hugo</generator><language>en</language><lastBuildDate>Sat, 09 May 2026 20:00:00 +0200</lastBuildDate><atom:link href="https://nerden.de/tags/rules_js/index.xml" rel="self" type="application/rss+xml"/><item><title>Frontend builds in Bazel with Vite and rules_js</title><link>https://nerden.de/bazel_frontend_vite/</link><pubDate>Sat, 09 May 2026 20:00:00 +0200</pubDate><guid>https://nerden.de/bazel_frontend_vite/</guid><description>&lt;p&gt;i build my frontends as SPAs with Vite inside a Bazel workspace alongside Go backends. &lt;code&gt;bazel build //...&lt;/code&gt; builds everything. The output is one JS bundle, one CSS file, and an index.html. The Go server serves it as static files, with &lt;code&gt;index.html&lt;/code&gt; returned for any path that doesn&amp;rsquo;t match a file on disk (so client-side routing works on refresh).&lt;/p&gt;
&lt;p&gt;i don&amp;rsquo;t use Next.js or any SSR framework.&lt;/p&gt;
&lt;h2 id="why-vite-not-nextjs"&gt;Why Vite, not Next.js&lt;a class="heading-anchor" href="#why-vite-not-nextjs"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The frontend runs in the browser. The browser runs JavaScript. So you write JavaScript for the browser and ship it as static files. The backend is Go, serving APIs over ConnectRPC or plain HTTP. Clean separation. The Go server serves the SPA as static files. Done.&lt;/p&gt;</description></item></channel></rss>