Búsqueda de sitios web

javascript - [Advertencia de Vue]: Error en el renderizado: "TypeError: Convirtiendo una estructura circular a JSON"


He creado con éxito un Componente de Archivo Único en Vue; no hay errores de compilación, sin embargo, cuando intento ver el componente (navegando a su enlace de ruta), la página esperada no se muestra y, en su lugar, obtengo un rastro de pila impreso en el navegador (Chrome) - usando el plugin Vue Devtools.

Aquí está la salida del seguimiento de pila en la consola del plugin Vue Devtools:

vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in render: 
log.js?1afd:24 [HMR] Waiting for update signal from WDS...
vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in render: "TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'DockPanel'
    |     property '_layout' -> object with constructor 'DockLayout'
    --- property '_parent' closes the circle"

found in

---> <Demo> at src/components/Demo.vue
       <App> at src/App.vue
         <Root>
warn @ vue.runtime.esm.js?2b0e:619
logError @ vue.runtime.esm.js?2b0e:1884
globalHandleError @ vue.runtime.esm.js?2b0e:1879
handleError @ vue.runtime.esm.js?2b0e:1839
Vue._render @ vue.runtime.esm.js?2b0e:3544
updateComponent @ vue.runtime.esm.js?2b0e:4060
get @ vue.runtime.esm.js?2b0e:4473
Watcher @ vue.runtime.esm.js?2b0e:4462
mountComponent @ vue.runtime.esm.js?2b0e:4067
Vue.$mount @ vue.runtime.esm.js?2b0e:8409
init @ vue.runtime.esm.js?2b0e:3118
merged @ vue.runtime.esm.js?2b0e:3301
createComponent @ vue.runtime.esm.js?2b0e:5972
createElm @ vue.runtime.esm.js?2b0e:5919
createChildren @ vue.runtime.esm.js?2b0e:6047
createElm @ vue.runtime.esm.js?2b0e:5948
patch @ vue.runtime.esm.js?2b0e:6471
Vue._update @ vue.runtime.esm.js?2b0e:3939
updateComponent @ vue.runtime.esm.js?2b0e:4060
get @ vue.runtime.esm.js?2b0e:4473
Watcher @ vue.runtime.esm.js?2b0e:4462
mountComponent @ vue.runtime.esm.js?2b0e:4067
Vue.$mount @ vue.runtime.esm.js?2b0e:8409
init @ vue.runtime.esm.js?2b0e:3118
createComponent @ vue.runtime.esm.js?2b0e:5972
createElm @ vue.runtime.esm.js?2b0e:5919
patch @ vue.runtime.esm.js?2b0e:6510
Vue._update @ vue.runtime.esm.js?2b0e:3939
updateComponent @ vue.runtime.esm.js?2b0e:4060
get @ vue.runtime.esm.js?2b0e:4473
Watcher @ vue.runtime.esm.js?2b0e:4462
mountComponent @ vue.runtime.esm.js?2b0e:4067
Vue.$mount @ vue.runtime.esm.js?2b0e:8409
(anonymous) @ main.ts?bc82:8
./src/main.ts @ app.js:5941
__webpack_require__ @ app.js:767
fn @ app.js:130
1 @ app.js:6015
__webpack_require__ @ app.js:767
(anonymous) @ app.js:902
(anonymous) @ app.js:905
Show 11 more frames
vue.runtime.esm.js?2b0e:1888 TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'DockPanel'
    |     property '_layout' -> object with constructor 'DockLayout'
    --- property '_parent' closes the circle
    at JSON.stringify (<anonymous>)
    at Proxy.toString (vue.runtime.esm.js?2b0e:94)
    at Proxy.render (eval at ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"4105b414-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/Demo.vue?vue&type=template&id=09260093&scoped=true& (app.js:2401), <anonymous>:10:25)
    at VueComponent.Vue._render (vue.runtime.esm.js?2b0e:3542)
    at VueComponent.updateComponent (vue.runtime.esm.js?2b0e:4060)
    at Watcher.get (vue.runtime.esm.js?2b0e:4473)
    at new Watcher (vue.runtime.esm.js?2b0e:4462)
    at mountComponent (vue.runtime.esm.js?2b0e:4067)
    at VueComponent.Vue.$mount (vue.runtime.esm.js?2b0e:8409)
    at init (vue.runtime.esm.js?2b0e:3118)
logError @ vue.runtime.esm.js?2b0e:1888
globalHandleError @ vue.runtime.esm.js?2b0e:1879
handleError @ vue.runtime.esm.js?2b0e:1839
Vue._render @ vue.runtime.esm.js?2b0e:3544
updateComponent @ vue.runtime.esm.js?2b0e:4060
get @ vue.runtime.esm.js?2b0e:4473
Watcher @ vue.runtime.esm.js?2b0e:4462
mountComponent @ vue.runtime.esm.js?2b0e:4067
Vue.$mount @ vue.runtime.esm.js?2b0e:8409
init @ vue.runtime.esm.js?2b0e:3118
merged @ vue.runtime.esm.js?2b0e:3301
createComponent @ vue.runtime.esm.js?2b0e:5972
createElm @ vue.runtime.esm.js?2b0e:5919
createChildren @ vue.runtime.esm.js?2b0e:6047
createElm @ vue.runtime.esm.js?2b0e:5948
patch @ vue.runtime.esm.js?2b0e:6471
Vue._update @ vue.runtime.esm.js?2b0e:3939
updateComponent @ vue.runtime.esm.js?2b0e:4060
get @ vue.runtime.esm.js?2b0e:4473
Watcher @ vue.runtime.esm.js?2b0e:4462
mountComponent @ vue.runtime.esm.js?2b0e:4067
Vue.$mount @ vue.runtime.esm.js?2b0e:8409
init @ vue.runtime.esm.js?2b0e:3118
createComponent @ vue.runtime.esm.js?2b0e:5972
createElm @ vue.runtime.esm.js?2b0e:5919
patch @ vue.runtime.esm.js?2b0e:6510
Vue._update @ vue.runtime.esm.js?2b0e:3939
updateComponent @ vue.runtime.esm.js?2b0e:4060
get @ vue.runtime.esm.js?2b0e:4473
Watcher @ vue.runtime.esm.js?2b0e:4462
mountComponent @ vue.runtime.esm.js?2b0e:4067
Vue.$mount @ vue.runtime.esm.js?2b0e:8409
(anonymous) @ main.ts?bc82:8
./src/main.ts @ app.js:5941
__webpack_require__ @ app.js:767
fn @ app.js:130
1 @ app.js:6015
__webpack_require__ @ app.js:767
(anonymous) @ app.js:902
(anonymous) @ app.js:905
Show 10 more frames
Demo.vue?96da:47 *** this actually ran

package.json

{
  "name": "client",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "test:unit": "vue-cli-service test:unit"
  },
  "dependencies": {
    "@phosphor/widgets": "^1.7.0",
    "axios": "^0.19.0",
    "core-js": "^2.6.5",
    "vue": "^2.6.10",
    "vue-class-component": "^7.0.2",
    "vue-property-decorator": "^8.1.0",
    "vue-router": "^3.0.3",
    "vuex": "^3.0.1"
  },
  "devDependencies": {
    "@types/chai": "^4.1.0",
    "@types/mocha": "^5.2.4",
    "@vue/cli-plugin-babel": "^3.8.0",
    "@vue/cli-plugin-eslint": "^3.8.0",
    "@vue/cli-plugin-typescript": "^3.8.0",
    "@vue/cli-plugin-unit-mocha": "^3.8.0",
    "@vue/cli-service": "^3.8.0",
    "@vue/eslint-config-airbnb": "^4.0.0",
    "@vue/eslint-config-typescript": "^4.0.0",
    "@vue/test-utils": "1.0.0-beta.29",
    "babel-eslint": "^10.0.1",
    "chai": "^4.1.2",
    "eslint": "^5.16.0",
    "eslint-plugin-vue": "^5.0.0",
    "less": "^3.9.0",
    "less-loader": "^5.0.0",
    "typescript": "^3.4.3",
    "vue-template-compiler": "^2.6.10"
  }
}

router.ts

import Vue from 'vue';
import Router from 'vue-router';
import Home from './views/Home.vue';
import Demo from './components/Demo.vue';

Vue.use(Router);

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home,
    },
    {
      path: '/demo',
      name: 'demo',
      component: Demo,
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (about.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import(/* webpackChunkName: "about" */ './views/About.vue'),
    },
  ],
});

Demo.vue

<template>
  <div class="demo">
    <h1>{{ title }}</h1>
    {{ dpanel }}
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { Widget, DockPanel } from '@phosphor/widgets';

@Component
export default class Demo extends Vue {
  @Prop() private title!: string;

  // apparently with typescript variant of vue, instance variables
  // are the equivalent of the vue 'data' object's attributes...
  dpanel:DockPanel = new DockPanel();

  components:any

  constructor() {
    super();
    this.components = {
      DockPanel,
    };
  }

  mounted() {
    const widget1 = new Widget();
    widget1.addClass('content');
    widget1.addClass('blue');
    widget1.title.label = 'Blue';
    widget1.title.closable = true;

    const widget2 = new Widget();
    widget2.addClass('content');
    widget2.addClass('red');
    widget2.title.label = 'Red';
    widget2.title.closable = true;

    this.dpanel.id = 'main';

    this.dpanel.addWidget(widget1);
    this.dpanel.addWidget(widget2);
    this.dpanel.update();
    console.log('*** this actually ran');
  }

  static setupPanels():void {
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less">
.content {
  border: 1px solid black;
  min-width: 50px;
  min-height: 50px;
}


.red {
  background: #E74C3C;
}


.yellow {
  background: #F1C40F;
}


.green {
  background: #27AE60;
}


.blue {
  background: #3498DB;
}


.p-DockTabPanel {
  padding-right: 2px;
  padding-bottom: 2px;
}


.p-DockTabPanel > .p-StackedPanel {
  padding: 10px;
  background: white;
  border: 1px solid #C0C0C0;
  border-top: none;
  box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
}


.p-DockPanel-overlay {
  background: rgba(255, 255, 255, 0.6);
  border: 1px dashed black;
}


.p-DockPanel-overlay.p-mod-root-top,
.p-DockPanel-overlay.p-mod-root-left,
.p-DockPanel-overlay.p-mod-root-right,
.p-DockPanel-overlay.p-mod-root-bottom,
.p-DockPanel-overlay.p-mod-root-center {
  border-width: 2px;
}


.p-TabBar {
  min-height: 24px;
  max-height: 24px;
}


.p-TabBar-header {
  display: none;
}


.p-TabBar-footer {
  flex: 0 0 1px;
  background: #C0C0C0;
}


.p-TabBar-content {
  min-width: 0;
  align-items: flex-end;
}


.p-TabBar-tab {
  flex: 0 1 125px;
  min-height: 20px;
  max-height: 20px;
  min-width: 35px;
  margin-left: -1px;
  border: 1px solid #C0C0C0;
  border-bottom: none;
  padding: 0px 10px;
  background: #E5E5E5;
  font: 12px Helvetica, Arial, sans-serif;
}


.p-TabBar-tab:first-child {
  margin-left: 0;
}


.p-TabBar-tab.p-mod-current {
  min-height: 23px;
  max-height: 23px;
  background: white;
  transform: translateY(1px);
}


.p-TabBar-tab:hover:not(.p-mod-current) {
  background: #F0F0F0;
}


.p-TabBar-tabIcon,
.p-TabBar-tabText,
.p-TabBar-tabCloseIcon {
  line-height: 20px;
}


.p-TabBar-tab.p-mod-closable > .p-TabBar-tabCloseIcon {
  margin-left: 4px;
}


.p-TabBar-tab.p-mod-closable > .p-TabBar-tabCloseIcon:before {
  content: '\f00d';
  font-family: FontAwesome;
}

.p-TabBar-tab.p-mod-drag-image {
  min-height: 23px;
  max-height: 23px;
  min-width: 125px;
  border: none;
  box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
  transform: translateX(-40%) translateY(-58%);
}

¿Qué está causando este error y cómo lo resuelvo (para poder representar correctamente los widgets, por ejemplo, como se muestra aquí)?

Respuesta #1

No estoy familiarizado con PhosphorJS, así que solo puedo proporcionar una explicación de lo que está pasando.

Parece que estás intentando renderizar una instancia de DockPanel en la plantilla haciendo {{ dpanel }}. Esto no funcionará. Esta "sintaxis de mustache" es para renderizar tipos de datos básicos como cadenas y números; si renderizas un objeto de esta manera, Vue mostrará la representación JSON de ese objeto llamando a JSON.stringify sobre él; en este caso, el objeto dpanel contiene referencias circulares, por lo que esto fallará.

Acabo de hojear la documentación de PhosphorJS. Parece que PhosphorJS no es una librería de componentes de Vue, así que tendrás que insertar el nodo DockPanel en el DOM tú mismo, probablemente en el hook mounted.

mounted() {
  this.$el.appendChild(this.dpanel.node)
},

destroyed() {
  this.dpanel.dispose()
}

De nuevo, no estoy familiarizado con PhosphorJS, así que este consejo podría no ser el más correcto.

Artículos relacionados