vue.jsnuxt.jsvuejs3houdininuxt3.js

Adding a houdini paintworklet in a nuxt3/vue app


I am trying to add a paintworklet to my application, but I am having a really hard time.

The worklet is a npm dependency, but worklets can't be inlined, they need to be registered like so:

CSS.paintWorklet.addModule('url/to/module.js');

I am having a hard time, because even though that currently works in my application, I am not sure if this is the right way to go about it, or if it will work in production. Currently, my url points to a file inside node_modules and I am not sure if nuxt will do anything with this.

I am currently doing this with a .client.js file inside the plugins folder. But they need an export default function(), but the worklet code does not have an export.

What I am currently trying to do, is tell nuxt somehow to grab certain files from node_modules and serve them as assets somehow, and then reference them some other way. But I cannot find any resources on this.

Any ideas would be appreciated.


Solution

  • If the file path is specified in a literal string, containing node_modules, the paint worklet might appear to work in development mode, but the worklet file will not be bundled in the build output:

    CSS.paintWorklet.addModule('./node_modules/extra-scalloped-border/worklet.js')
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                               ❌ file not bundled in build output
    

    Solution: Import the file

    Importing a file enables the bundler to track the file, and include it in the build output. Nuxt 3 uses Vite by default, and the Vite docs describe how to import the file to use with paint worklets:

    Explicit URL Imports

    Assets that are not included in the internal list or in assetsInclude, can be explicitly imported as an URL using the ?url suffix. This is useful, for example, to import Houdini Paint Worklets.

    import workletURL from 'extra-scalloped-border/worklet.js?url'
    CSS.paintWorklet.addModule(workletURL)
    

    Since the CSS.paintWorklet API is only available in the browser, make sure to use this in the mounted() hook, which only occurs client-side:

    import workletURL from 'extra-scalloped-border/worklet.js?url'
    
    export default {
      mounted() {
        CSS.paintWorklet.addModule(workletURL)
      }
    }
    

    demo