Nathan Lamont

Notes to Self

Making a Vue/Nuxt Module

You wanted your work on "shared element transitions" to be re-usable by others, so you began work on creating a Nuxt module using their "starter template."

npx nuxi init -t module vue-shared-element-transition

This includes a "playground" where an example app lives to test your module.

The pieces for shared element transitions were:

  • a composable that does most of the work
  • a plugin to handle scroll behavior
  • a component for cases where your which to apply the transition to something other than a page

This seemed to work well. Notably, the weird callback stuff (diagrammed here: [[Shared Element Transitions + Scroll Behavior.canvas]]) was not necessary as, in the playground, the scrollBehavior hook was being called at the "right" time.

But you realized that there might be utility for a plain Vue module, not just Nuxt. Your Nuxt module would then use this Vue module.

There doesn't seem to be an official starter template for Vue modules. You basically took this "boilerplate" and removed the storybook parts (storybook is a big tool for documenting/testing components).

This template looks lighter but you have not tried it yet.

You got the Vue module working. The problem came when you wanted to test it in the Nuxt module.

The correct way to do this is with npm/yarn link. You go to the directory of the project you want to link to, in this case the Vue module. You type

~/vue-shared-element-transition/ > yarn link

Then you to the directory you want to link from, as if the module were installed:

~/nuxt-shared-element-transition/ > yarn link vue-shared-element-transition

However, when attempting to import in the code, e.g.

import { useSharedElementTransition } from "vue-shared-element-transition";

You could get an error message stating that the file couldn't be found, even though it correctly listed the actual path to the file it was looking for.

There is some symLink setting for some part of vite, but it doesn't appear to be exposed in Nuxt? You are about to attempt to simplify the problem by creating a new Vue component and a new Nuxt component to more destructively experiment with.

Update

When you attempted to recreate with bare projects, you saw additional info pointing you to the following solution.

For the link to work, you need to add the following to nuxt config:

import { searchForWorkspaceRoot } from 'vite'

export default defineNuxtConfig({
  // ...
  vite: {
    server: {
      fs: {
        strict: false
      }
    }
  }
})

You did this in playground's nuxt.config.ts -- doesn't seem necessary to build though? Not sure.

!warning May be obvious, but you will need to release the vue component in order to release the nuxt component. Don't forget.

** CONFIRMED ** The above worked as a fix for the real modules I was working on. Next steps:

  1. Review packages and methods from both "boilerplate" vue projects you used. VitePress used on the second project seems like a useful addition, as it can be used to both test, demonstrate, and document the component.
  2. Once settled:
  3. Init git; ensure that .gitinit is properly configured
  4. Ensure that linting/prettying is in place
  5. Create demonstration in Vue project (like demo in Nuxt project)
  6. Create documentation in Vue Project
  7. Explore vue router - that's where scrollPosition comes in, so maybe should not be limited to nuxt
  8. Publish
  9. Repeat for nuxt project

Unanticipated additional work:

  • The way to have a module that automatically can be used universally in vue is to have its main library export a default with an import function, e.g. return default { import(app:Vue): {} }. There are two kinds of modules you may need to support, umd and esm (which I guess just uses an es file extension) but umd is weird about exporting both default (for magic) and named exports. You are going to ignore umd for now. EDIT: no you figured it out, kind of. vue3-boilerplate had es and umd flipped (umd is for require, es cannot be required). Can't export default, so have to export named import function, then import that import function and use it from plugin.
  • There is some issue with a lynchpin in your shared-element-transition: you are using "globals" in the sharedElementTransition composable to store data about the elements that are transitioning. Not good for es module as it seems one of the globals is reduced to h, and a different h is prepended. The composable is called from different components -- how else to share that info (both from and to elements must be considered). Note: you refactored consts into single object g and the different h import that was prepended magically went away. WTF.

Unexpected complexity:

You need to have

  • Vue Project with
    • VitePress site built in to test and doc
  • External example vue project to test import
  • Nuxt Project with
    • Nuxt playground site built in
  • External example nuxt project to test import
PropertyTypeDefaultDescription
speednumber222Speed of the transition, in milliseconds
groupstring"page"An arbitrary group name to associate transitions with. Transitions belonging to different groups will not affect each other.
comparatorComparatorType* see noteA comparator function to use when considering Relative Slide transitions.
xstring"25%"A valid CSS unit value for horizontal animation on Relative Slide transitions.
ystring"0%"A valid CSS unit value for vertical animation on Relative Slide transitions.