nuxt / nuxt

The Intuitive Vue Framework.
https://nuxt.com
MIT License
55.06k stars 5.04k forks source link

missing class functions with ssr `npm run build` ('... is not a function') #15360

Closed wagpa closed 2 years ago

wagpa commented 2 years ago

Environment

Additional Packages that might be helpful to know

Reproduction

in a component setup script

// https://github.com/ueberdosis/tiptap/blob/main/packages/extension-document/src/document.ts
// https://github.com/ueberdosis/tiptap/blob/cd78f1d863f2437739e80ad1a54be52008f3cfe3/packages/core/src/Node.ts#L522
import Document from "@tiptap/extension-document";

// from https://stackoverflow.com/a/31055217/10619052
function getAllFuncs(toCheck: any) {
  const props = [];
  let obj = toCheck;
  do {
    props.push(...Object.getOwnPropertyNames(obj));
  } while (obj = Object.getPrototypeOf(obj));

  return props.sort().filter((e, i, arr) => {
    if (e!=arr[i+1] && typeof toCheck[e] == 'function') return true;
  });
}

console.log('document functions', getAllFuncs(Document))

Describe the bug

When calling Document.configure(...) on server, it throws the error [nuxt] [request error] [unhandled] [500] Document.configure is not a function. On the client this works. When i try to output all functions of the Document (see above), i get the following outputs:

In server console

document functions [
  '__defineGetter__',
  '__defineSetter__',
  '__lookupGetter__',
  '__lookupSetter__',
  'constructor',
  'hasOwnProperty',
  'isPrototypeOf',
  'propertyIsEnumerable',
  'toLocaleString',
  'toString',
  'valueOf'
]

In browser console (cropped)

"__defineGetter__"
"__defineSetter__"
"__lookupGetter__"
"__lookupSetter__"
"configure"
"constructor"
"extend"
"hasOwnProperty"
"isPrototypeOf"
"propertyIsEnumerable"
"toLocaleString"
"toString"
"valueOf"

As you can see, the expected class functions configure and extend are missing in the server console printout. Calling the functions on the server gives the described error message.

Additional context

I'm not sure, if this is a nuxt 3, vue 3 or tiptap 2 error. But as the tiptap 2 class definition seems to be pretty simple, i don't think, this is a tiptap 2 issue.

To complicate things, when i run the same code with npm run dev, it works as expected. Running it with npm run build and then node .\.output\server\index.mjs gives the error.

I'm happy for any lead to the cause and will provide further information if needs be.

Logs

[nuxt] [request error] [unhandled] [500] Document.configure is not a function
  at titleExtensions (/C:/Users/.../website/.output/server/chunks/server.mjs:6427:14)
  at ReactiveEffect.fn (/C:/Users/.../website/.output/server/chunks/server.mjs:6520:35)
  at ReactiveEffect.run (C:\Users\...\website\.output\server\node_modules\@vue\reactivity\dist\reactivity.cjs.js:170:25)
  at get value [as value] (C:\Users\...\website\.output\server\node_modules\@vue\reactivity\dist\reactivity.cjs.js:1141:39)
  at unref (C:\Users\...\website\.output\server\node_modules\@vue\reactivity\dist\reactivity.cjs.js:1047:29)
  at /C:/Users/.../website/.output/server/chunks/server.mjs:6581:198
  at renderFnWithContext (C:\Users\...\website\.output\server\node_modules\@vue\runtime-core\dist\runtime-core.cjs.js:851:19)
  at ssrRenderSlotInner (C:\Users\...\website\.output\server\node_modules\@vue\server-renderer\dist\server-renderer.cjs.js:628:21)
  at ssrRenderSlot (C:\Users\...\Web\website\.output\server\node_modules\@vue\server-renderer\dist\server-renderer.cjs.js:618:5)
  at _sfc_ssrRender$1 (/C:/Users/.../website/.output/server/chunks/server.mjs:3739:3)
wagpa commented 2 years ago

Updated to Nuxt Version 3.0.0-rc.13 but problem is still there

wagpa commented 2 years ago

I tested some stuff. Maybe someone with more knowledge about JS and Node (v18.12.0) has an idea. For some reason, the DocumentClone works as intended, while Document is missing its functions.

Is JS dropping information about Document when imported?

import Document from '@tiptap/extension-document';
import {Node} from "@tiptap/core";

console.log('[debug] node definition', Node.prototype, Node.prototype.configure)
console.log('[debug] document type', typeof Document, Document instanceof Node)
let testNode = Node.create({ name: 'test' })
let testNode2 = new Node({ name: 'test' })
let DocumentClone = Node.create({
    name: 'doc',
    topNode: true,
    content: 'block+',
});
console.log('[debug] test node type', typeof testNode, testNode instanceof Node, testNode.extend)
console.log('[debug] test node 2 type', typeof testNode2, testNode2 instanceof Node, testNode2.extend)
console.log('[debug] document definition', Object.getPrototypeOf(Document), Object.getPrototypeOf(Document).configure, Document.extend)
console.log('[debug] document clone definition', Object.getPrototypeOf(DocumentClone), Object.getPrototypeOf(DocumentClone).configure, DocumentClone.extend)

with @tiptap/extension-document defining

import { Node } from '@tiptap/core'

export const Document = Node.create({
  name: 'doc',
  topNode: true,
  content: 'block+',
})

with

class Node {
...
  static create(config = {}) {
      return new Node(config);
  }
}

Prints

[debug] node definition {} [Function: configure]
[debug] document type object false
[debug] test node type object true [Function: extend]
[debug] test node 2 type object true [Function: extend]
[debug] document definition [Object: null prototype] {} undefined undefined
[debug] document clone definition {} [Function: configure] [Function: extend]
wagpa commented 2 years ago

I finally got it working.

After changing the import to

// not working with 'npm run build': import Document from '@tiptap/extension-document';
import { Document } from '@tiptap/extension-document';
// should also work: import * as ExtensionDocument from '@tiptap/extension-document'; const Document = ExtensionDocument.Document;

the imported object has all the class methods as expected.

As this doesn't seem to be a direct problem with nuxt, im closing this issue. But i hopes it helps someone, if they encounter a similar problem.