Using Partytown to load third-party scripts in SolidStart

Partytown provides a novel approach to load third-party scripts such as analytics in the background using web workers. This offloads non-essential scripts off the main thread speeding up your web app. This does not come without trade-offs though.

Getting Started

Create a new SolidStart project.

Terminal window
pnpm create solid

Install Partytown.

Terminal window
pnpm install @builder.io/partytown

Configuring Partytown

We need to serve Partytown’s scripts. Partytown provides a Vite plugin to copy files to our public folder serve them during development from Vite’s dev server, however I ran into issues with this approach with some deployment presets. A Nitro module similar to @nuxtjs/partytown would probably be ideal.

import { partytownVite } from "@builder.io/partytown/utils"
import { defineConfig } from "@solidjs/start/config"
import path from "path"
export default defineConfig({
plugins: [
partytownVite({
// The absolute path to your build output public directory
dest: path.join(__dirname, ".output/public", "~partytown"),
}),
],
})

Instead of the Vite plugin, I opted for the low tech approach. I added a script to my package.json to copy the files during build step. Be sure to run the script once locally to generate the files in development.

package.json
{
"scripts": {
"build": "pnpm run partytown && vinxi build",
"partytown": "partytown copylib public/~partytown"
}
}

Additionally I added the Partytown folder to my .gitignore so it is not committed to my repo.

.gitignore
# Partytown
public/~partytown

You can run pnpm run build to build your project and see the Partytown scripts in your public folder, .output/public/~partytown.

Next we need to load Partytown’s scripts in our app. To do this we can use <Assets> from Solid to add the scripts to our head.

With Partytown, setting a <script> type to "text/partytown" will tell Partytown to run the script.

src/app.tsx
import { partytownSnippet } from "@builder.io/partytown/integration"
import { Assets } from "solid-js/web"
export default function App() {
return (
<Router
root={(props) => (
<>
{/* Partytown scripts */}
<Assets>
<script>{partytownSnippet()}</script>
<script type="text/partytown">{"console.log('Hello from Partytown!')"}</script>
</Assets>
<Nav />
<Suspense>{props.children}</Suspense>
</>
)}
>
<FileRoutes />
</Router>
)
}

You should see “Hello from Partytown!” in your console.

Using Partytown

Now that we have Partytown setup we can use it to run our code in a web worker. A common usecase for this is for analytics. Here is an example using Google Analytics with forwarding events.

src/app.tsx
<Assets>
<script>{partytownSnippet()}</script>
<script type="text/partytown">{`partytown = { forward: ['gtag', 'dataLayer.push'] }`}</script>
<script type="text/partytown" src="https://www.googletagmanager.com/gtag/js?id=YOUR-ID-HERE"></script>
<script type="text/partytown">
{`window.dataLayer = window.dataLayer || [];
window.gtag = function () {
dataLayer.push(arguments);
};
window.gtag('js', new Date());
window. gtag('config', 'YOUR-ID-HERE');`}
</script>
</Assets>

Inspect your chrome network tab and you should see the Google Analytics script being loaded from Partytown service worker as well as requests being forwarded via proxytown.

Chrome Network Tab with Partytown requests