как отрисовывать vue-компонент в файле vue с помощью (vue-server-renderer)

#javascript #node.js #vue.js #nuxt.js #vue-server-renderer

#javascript #node.js #vue.js #nuxt.js #vue-server-renderer

Вопрос:

Я хочу начать компонент рендеринга с vuejs

У меня есть простой сервер узлов

    const Vue = require('vue');
const server = require('express')();
const template = require('fs').readFileSync('index.template.html', 'utf-8');
const renderer = require('vue-server-renderer')
    .createRenderer({
        template
    })
const context = {
    title: 'vue ssr',
    meta: `
        <meta name="keyword" content="vue,ssr">
        <meta name="description" content="vue srr demo">
    `,
};
server.get('/test2', (req, res) => {
    res.end("test");
});

server.get('/test', (req, res) => {
    const app = new Vue({
        data: {
            url: req.url
        },
        template: `<div>The visited URL is: {{ url }}</div>`,
    });
    renderer
        .renderToString(app, context,(err, html) => {
            //console.log('app', app )
            if (err) {
                res.status(500).end('Internal Server Error')
                return;
            }
            res.end(html);
        });
})

server.listen(8080);
 

URL: localhost:8080/test работает
введите описание изображения здесь

Моя проблема касается рендеринга впереди. Я использую nuxt.js , и я тестирую с помощью простого пути к странице: project/pages/test.vue

//// File test.vue для отображения рендеринга

 <template>
  <div>
    test
  </div>
</template>
<script>
  export default {
    async asyncData({ params }) {
      try {
        let result = await fetch(`http://localhost:8080/test`)
          .then(res => res.json())
          .then(data => data);
        console.log('result', result)
        return `<span> test </span>`;
      } catch (e) {
        console.error("SOMETHING WENT WRONG :"   e);
        return `<span> error </span>`;
      }
    },
  }
</script>
 

Результат вызова:

 {
  size: 0,
  timeout: 0,
  [Symbol(Body internals)]:
   { body:
      PassThrough {
        _readableState: [ReadableState],
        readable: true,
        domain: null,
        _events: [Object],
        _eventsCount: 2,
        _maxListeners: undefined,
        _writableState: [WritableState],
        writable: false,
        allowHalfOpen: true,
        _transformState: [Object] },
     disturbed: false,
     error: null },
  [Symbol(Response internals)]:
   { url: 'http://localhost:8080/test',
     status: 200,
     statusText: 'OK',
     headers: Headers { [Symbol(map)]: [Object] },
     counter: 0 } }
 

Мой вопрос в том, как отобразить содержимое вызова в моем представлении. Я не нашел элемент ответа.
Спасибо

Редактировать 1: для исправления отображения простой строки или объекта в порядке #НАЗАД

 server.get('/test/string', (req, res) => {
    res.json('simple chaine ')
})
server.get('/test/object', (req, res) => {
    res.json({ id: 1, name: 'un object' })
})
 

#ФРОНТ

 <template>
  <div class="container">
    <p v-if="data_error">{{ data_error }}</p>

    <h2>ASYNC Test sur une chaine de caractère</h2>
    <div><p>Display example string: {{ data_string }}</p></div>

    <h2>ASYNC Test sur un object</h2>
    <div><pre>{{ data_object }}</pre></div>
  </div>
</template>
<script>
  export default {
    async asyncData() {
      try {
        const responseString = await fetch('http://localhost:8080/test/string');
        const string = await responseString.json();

        const responseObject = await fetch('http://localhost:8080/test/object');
        const object = await responseObject.json();

        return {
          data_string: JSON.parse(JSON.stringify(string)),
          data_object: JSON.parse(JSON.stringify(object)),
          data_error: null,
        }
      } catch (e) {
        return { data_error: e }
      }
    },
  }
</script>
 

Но если я хочу отобразить компонент, у меня есть проблема
#НАЗАД

 server.get('/test/count', (req, res) => {
    const app = new Vue({
        data: {
            count: 0
        },
        methods: {
            counter() {
                this.count  
            }
        },
        template: `<div>
            <button v-on:click="counter">click</button>
            The visited URL is: {{ count }}
        </div>`,
    });

    renderer.renderToString(app).then(html => {
        console.log(html)
        res.json(html);
    }).catch(err => {
        res.status(500).end('Internal Server Error')
        console.error(err)
    })
})
 

#FRONT (не работает, у меня просто html, а не событие, я не знаю, возможно ли это)

 <template>
  <div v-html="data_compCount"></div>
</template>
<script>
  export default {
    async asyncData({ params }) {
      try {
        const responseCounter = await fetch('http://localhost:8080/test/count');
        const compCount = await responseCounter.json();
        return {
          data_compCount: JSON.parse(JSON.stringify(compCount)),
          data_error: null,
        }
      } catch (e) {
        console.error("SOMETHING WENT WRONG :"   e);
        return `<span> error </span>`;
      }
    },
  }
</script> 
 

Ответ №1:

Я разберу это на два простых шага:

Шаг 1: отображение значения (любого значения) в компоненте vue:

 <template>
  <div>
    Display example string: {{ example_string }}
    Another way to display a string: 
    <span v-text="example_string"></span>

    A way to display an object (for debugging purposes mostly):
    <pre>{{example_data}}</pre>
  </div>
</template>
<script>
export default {
   data() {
       return {
          example_string: 'This is an example string',
          example_data: { id: 1, name: 'Example' }
       }
   }
}
</script>
 

Шаг 2: получение ответа от сервера и использование данных:

 <script>
export default {
    data() { 
        return {
            // we will fetch data from server and store them
            // in example_data. 
            example_data: null
        }
    },

    // To ensure the data gets loaded on page start/component initialisation:
    mounted() {
        this.loadData();
        // or: this.loadData2();
    },

    methods: { 
       // async await example:
       async loadData() {
          var data = await (fetch(url).then(response => response.json());

          this.example_data = data;
       },

       // without async/await:
       loadData2() {
          fetch(url).then(response => response.json()).then(data => {
             this.example_data = data;
          });
       }
    },

}
</script>
 

Редактировать:
функция data() является специальной функцией Vue. Он возвращает объект со значениями, которые будут доступны внутри вашего шаблона vue и для this объекта во всех других функциях. Функции, которые вы создали, чтобы возвращать значение, должны быть переписаны следующим образом. Пожалуйста, обратите внимание, что я не могу протестировать какой-либо серверный сервер, поэтому интерпретируйте эти примеры кода как примеры:

#НАЗАД:

 <template>
  <div class="container">
    <p v-if="data_error">{{ data_error }}</p>

    <h2>ASYNC Test sur une chaine de caractère</h2>
    <div><p>Display example string: {{ data_string }}</p></div>

    <h2>ASYNC Test sur un object</h2>
    <div><pre>{{ data_object }}</pre></div>
  </div>
</template>
<script>
  export default {
    // Vue's special data function
    data() {
       return {
           data_string: null,
           data_object: null,
           data_error: null
       }
    },
    // Vue's special 'mounted' (initialisation function)
    mounted() {
        // We want to load data when the page loads.
        this.asyncData();
    },

    methods: { 
      // Always write your function inside this methods object.
      async asyncData() {
        try {
          const responseString = await fetch('http://localhost:8080/test/string');
          const string = await responseString.json();

          const responseObject = await fetch('http://localhost:8080/test/object');
          const object = await responseObject.json();

          this.data_string = string;
          this.data_object = object;
          this.data_error = null;
        } catch (e) {
          console.error("SOMETHING WENT WRONG :"   e);
          this.data_error = e;
        }
      }
    }
  }
</script>
 

#ФРОНТ:

 <template>
  <div v-html="data_compCount"></div>
</template>
<script>
  export default {
    // Vue data function.
    data() {
       return {
           data_compCount: null
       }
    },
    // Vue mounted function
    mounted() {
       this.asyncData();
    },
    methods: { 
      async asyncData({ params }) {
        try {
          const responseCounter = await fetch('http://localhost:8080/test/count');
          const compCount = await responseCounter.json();

          this.data_compCount = compCount;
          this.data_error = null;
        } catch (e) {
          console.error("SOMETHING WENT WRONG :"   e);
          this.data_error = e;
        }
      }
    }
  }
</script> 
 

Комментарии:

1. 1) Есть ли у вас пример для вашего бэкэнда, потому что ваш асинхронный метод не соответствует моим данным. 2) Вы визуализировали простые данные или простую строку, но если вы визуализируете компонент, как вы можете это сделать? потому что в вашем примере с моим бэкэндом это не работает. Спасибо

2. Рад видеть, что вы добились некоторого прогресса. Я обновил ответ, чтобы отразить некоторые внесенные вами изменения. Я вижу, вы также хотите заниматься рендерингом на стороне сервера и довольно новичок в Vue. Я бы посоветовал вам сначала сосредоточиться на создании рабочего интерфейса vue-приложения, чтобы вы поняли основы, а затем, если вы чувствуете себя достаточно комфортно, решите добавить возможности рендеринга на стороне сервера в ваше приложение. Удачи!