Insert ESM Module as custom script tag with contents with Nuxt v2

Tags

Say you want to have Nuxt properly handle client-side only ECMAScript as part of the build, and allow to inject your own build variables. Something more than simply have a script tag load a JavaScript file from the static/ folder.

This is for Nuxt v2

I know that in 2024, Nuxt and Vue went through major version bumps.

As of still, the documentation is available on a different domain name:

For Nuxt v2, the domain name is v2.nuxt.com: https://v2.nuxt.com/docs/

But I had this project started in 2020 before COVID and all the stress we went through, and after that I had my parental leave.

That said, I wanted to add new ideas to my 2020 code base. Essentially working around Nuxt builder (WebPack) by wrangling things differently.

It's possible.

Desired outcome

Say for example I wanted to have the following as part of every page to have a script tag like the following:

<script type="module" defer>
  //
  // Anything you might want. That's just something I've done.
  //
  import { registerCustomElement } from 'https://renoirb.com/esm-modules/element-utils.mjs'
  import NoticeBoxElement from 'https://renoirb.com/esm-modules/notice-box-element.mjs'
  registerCustomElement(window, 'rb-notice-box', NoticeBoxElement)
</script>

In my case, it was to load Web Components outside of Nuxt build.

Caution though, we can't do much more than this. We can't have dynamic variables from that code block because Nuxt Build and the compiler will probably try to grab it, so we can instert things, but it has to be passed as a string.

Why I wanted to do this?

That's something I had to do, and may have to return to to get where I want to go with this web site. Since I had to delete the code, I’ve made this to keep it somewhere.

My plan for this site is to have the least amount of code as possible in this repository. This repository already doesn't contain the Images assets, it helps to save space and I can control where the images gets loaded. I'd like this site to only contain the logic for routes, the content, and everything else packaged and tested. I want t stretch this as far as I can get.

That said, In Nuxt v2 docs

Basically, In some situation you might want to have the client-side JavaScript to contain variables from during the nuxt build as part of the

Following the documentation trail

For this, we have to read up Nuxt API at nuxt.config.ts head configuration, the example are a bit too simplistic.

export default {
  head: {
    titleTemplate: '%s - My Site',
    meta: [
      // ...
    ],
    link: [
      // But what's the format??
    ],
  },
}

But for script, we have to look at Nuxt meta module that's using Vue Meta, but unfortunately it's the source we have to dig into.

Quoting VueMeta Nuxt module documentation at "script"

Each item in the array maps to a newly-created

{
  // But in Nuxt, that's called "head"
  metaInfo: {
    script: [
      // Neat! But that's not quite it.
      { src: 'https://cdn.jsdelivr.net/npm/vue/dist/vue.js', async: true, defer: true }
    ],
  }
}
<script
  src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"
  async
  defer
></script>

But that's not what I wanted.

What I want is

<script type="module">// Do things here!</script>

End Result

Configuration

Here are the changes I've made on my nuxt.config.ts.

import { NuxtConfig } from '@nuxt/types'

// ...

const THE_SCRIPT_CONTENTS_STATIC_STRING = `
import { registerCustomElement } from 'https://renoirb.com/esm-modules/element-utils.mjs'
import NoticeBoxElement from 'https://renoirb.com/esm-modules/notice-box-element.mjs'
registerCustomElement(window, 'rb-notice-box', NoticeBoxElement)
`

const main: NuxtConfig = {
  head: {
    // ...
    script: [
      // ...
      {
        type: 'module',
        vmid: 'load-esm-modules-separately-please',
        body: true,
        defer: true,
        innerHTML: THE_SCRIPT_CONTENTS_STATIC_STRING,
      }
    ],
    __dangerouslyDisableSanitizers: [
      /* YOLO. Plus, I don't want WebPack to inline and mangle what's here. */ 'script',
    ],
  },
}

export default main