Задать вопрос
  • Почему разное значение переменной в NUXT 3?

    @null_object
    Это так не работает. Передача состояние с сервера на клиент не происходит сама по себе, его нужно прокидывать, для этого в Nuxt сделано много утилит (useAsyncData, useLazyAsyncData, useNuxtData, useState и т.д.), которые пляшут вокруг большого сериализуемого стейта, который на клиенте обратно десериализуется. И useFetch использует это под капотом.

    То есть ваш код работает так:
    1. На сервере вызывается функция getPosts
    2. Выполняется запрос, результат сохраняется в стейт накста, в total.value записывается значение
    3. На клиенте вызывается функция getPosts
    4. Но тут уже запрос не выполняется, только вычитывается значение из стейта, соответственно onResponse не вызывается

    Решить это можно несколькими путями: создать отдельный стейт для total, либо к ответу в onResponse дописывать значение заголовка.

    <script setup lang="ts">
    const { data } = useFetch('https://jsonplaceholder.typicode.com/todos/1', {
      onResponse({ response, options }) {
        // дописываем в data значение заголовка
        response._data.type = response.headers.get('Content-Type');;
      },
    });
    </script>


    Сериализованное состояние, которое идет с сервера на клиент можно дебажить через Nuxt Devtools
    67ae28550973e616213331.png
    Ответ написан
  • Как задеплоить vite react сайт на хостинг timeweb?

    @null_object
    Если вы делали обычное SPA приложение, после билда которого у вас есть набор html, css, js файлов, то просто загрузить их на vps недостаточно, нужен веб-сервер, который эти файлы будет раздавать. Часто для этого ставять Nginx, в конфиге которого указывается директория с собранными файлами, например так
    server {
        listen 80;
        server_name your-domain.com;
    
        root /path/to/your/dist;
        index index.html;
    
        location / {
            try_files $uri /index.html;
        }
    }


    Если нет желания разбираться с конфигами, то проще всего воспользоваться сервисами, которые умеют автоматически деплоить проекты из репозитория, те же Apps у Timeweb
    Ответ написан
    Комментировать
  • Чем так страшен верхне-уровненый await в script setup?

    @null_object
    Если у вас версия vue >3.2, то страшного ничего нет. Проблема в том, что у vue рендер синхронный и после первого await в setup теряется контекст монтируемого компонента, который используется много где под капотом - реактивные функция вроде watch, хуки жизненного цикла и т.д. Это можно обойти, а начиная с vue 3.2 это сделано на уровне компилятора sfc. Подробно с примерами про это написано тут.

    Если говорить про useAsyncData - это уже композабл самого nuxt, нужный в первую очередь для дедупликации данных при ssr. По умолчанию данные запрашиваются на сервере, серилизуются и передаются вместе с html (пример на скриншоте). Этот композабл можно использовать и без await, при условии, что запрос вам нужно выполнять только на клиенте (server: false), тогда обработку ошибок надо будет делать через watch(error, ...)
    67659c49b753a027017230.png
    Ответ написан
    1 комментарий
  • Как правильно типизировать vue generic components?

    @null_object
    const virtualizationContainer = ref<typeof VVirtualizationContainer | null>(null);


    playground

    6742b6fc6e199037664340.png
    Ответ написан
    3 комментария
  • Как можно вытащить типы пропсов из определения компонента?

    @null_object Автор вопроса
    type ComponentProps<ComponentDefinition> = ComponentDefinition extends { new (): { $props: infer P } } ? P : never;
    Ответ написан
    Комментировать
  • Как сгруппировать значения массива?

    @null_object
    const array = ['part1-item1', 'part1-item2', 'part2-item1', 'part3-item1'];
    
    const result = array.reduce((acc, rec) => {
      const [part, item] = rec.split('-');
      if (!acc[part]) {
        acc[part] = [item];
      } else {
        acc[part].push(item);
      }
      return acc;
    }, {});
    Ответ написан
    2 комментария
  • Возможно ли впихнуть фронтенд на nuxt.js и бекенд на express.js на один сервер?

    @null_object
    Для чего-то небольшого можно обойтись встроенными возможностями Nuxt, он позволяет делать бэкенд рядом с фронтедом с помощью своего сервера - Nitro. Подробнее об этом есть в документации Nuxt и документации Nitro.

    Если нужно, Nitro может использовать и другие решения (Express, Hono и др.) про это есть видео + дока.
    Ответ написан
    Комментировать
  • Как заставить hmr в vite подключатсья по wss?

    @null_object
    Как уже написал Aetae, конфигурацией протокола занимается nuxt, но монкипатчить не обязательно, переопределить конфиг можно через хук, например так
    export default defineNuxtConfig({
      hooks: {
        'vite:extendConfig': function (vite) {
          vite.server.hmr = {
            protocol: 'wss',
          };
        },
      },
    });
    Ответ написан
    Комментировать
  • Как правильно отобразить компоненты в Components Tree Nuxt 3?

    @null_object
    Это стандартное поведение компонента <NuxtPage /> и не является проблемой, он внутри себя использует <RouterView /> из vue-router в который добавляется внутренняя логика Nuxt (например добавление Transitions если они указаны в настройках). Anonymous Component на самом деле - компонент RouteProvider, который занимается перерисовкой страниц. В общем, просто обертка фреймворка для роутинга.

    RouteProvider добавляется тут. Код самого провайдера можно тут посмотреть.
    Ответ написан
    Комментировать
  • Есть ли рекомендуемый порядок следования атрибутов во vue?

    @null_object
    Еще есть vue-eslint правило по порядку атрибутов
    Ответ написан
    Комментировать
  • Как лучше переписать условие?

    @null_object
    export const Footer = (props?: IFooterProps) => {
        return (
            <View style={styles.container}>
                {props && props.button ? (
                  <>
                     <RNHoleView style={styles.background} holes={[hole]}>
                          <View style={styles.maskBorder}></View>
                      </RNHoleView>
                      {props.button}
                   </>
                ) : (
                  <View style={styles.background}></View>
                )}
            </View>
        );
    };
    Ответ написан
    3 комментария
  • Как добавить количество wc -l в конец строки в виде значения?

    @null_object
    echo -n "текущее количество нескрытых файлов и директорий в /usr/bin равно:" > results.txt | ls /usr/bin  | wc -l >>  results.txt
    Ответ написан
    3 комментария
  • Vue 3 Composition API как обратиться к функции через this.$refs?

    @null_object
    Чтобы напрямую вызывать методы инстанса компонента, нужно методы сделать публичными. Для этого есть expose в Options API и defineExpose для Composition API

    Child.vue
    <script setup>
    const foo = ref('foo')
    const bar = () => console.log('bar')
    
    defineExpose({
      foo,
      bar,
    })
    </script>

    Parent.vue
    <template>
      <Child ref="child" />
    </template>
    
    <script setup>
    const child = ref(null);
    
    onMounted(() => {
      console.log(child.value.foo)
      console.log(child.value.bar())
    })
    </script>


    Т. е. без доработок код из этого репозитория не заработает
    Ответ написан
    Комментировать
  • Как работает runtime config в Nuxt 3?

    @null_object
    Под рантайм конфигурацией понимаются переменные окружения, которые может подхватить приложение после сборки. Если собрать обычное SPA, значения этих переменных зашиваются на этапе сборки прямо в код и их поменять можно только повторной пересборкой.

    То, что вы в консоли установили переменную окружения и она сразу попала в приложения - скорее всего совпадение. Девопсы правильно сказали про их статичность, так что по какой-то причине у вас сработал hmr и подхватились новые переменные.

    Найти конкретную причину всех возможных триггеров для перезагрузки в коде будет достаточно затруднительно, т.к. эта логика сильно размазана по пакетам Nuxt -> Nitro -> Vite -> Chokidar
    Ответ написан
    Комментировать
  • Как использовать хуки NUXT в модулях?

    @null_object
    Если нужны именно хуки
    const nuxtApp = useNuxtApp();
    
    const loadingStartHook = nuxtApp.hook('page:loading:start', () => {
      ...
    });
    
    const loadingFinishHook = nuxtApp.hook('page:loading:end', () => {
      ...
    });
    
    const unsubError = nuxtApp.hook('vue:error', () => ...)


    В какой-то из версий добавили встроенный композабл useLoadingIndicator . Это удобная обертка над этими хуками, можно в исходниках глянуть.

    Использовать достаточно просто
    const { progress, isLoading } = useLoadingIndicator();


    Тут можно посмотреть пример кастомного индикатора
    Ответ написан
    Комментировать
  • Nuxt Supabase Как решить ошибку 500 "client.from is not a function"?

    @null_object
    serverSupabaseClient возвращает Promise, нужно добавить await

    import { serverSupabaseClient } from '#supabase/server'
    
    export default eventHandler(async (event) => {
        const client = await serverSupabaseClient(event)
        const { data } = await client.from('users').select("*")
        return { users: data }
    })
    Ответ написан
  • Почему подвисают дочерние компоненты vue?

    @null_object
    Тормозить начинает из-за большого количества нод в dom дереве. Решается использование "виртуального скролла", суть которого заключается в отрисовки только видимых элементов.

    Подробнее - https://www.patterns.dev/vanilla/virtual-lists

    Утилита для Vue - https://vueuse.org/core/useVirtualList/
    Ответ написан
    1 комментарий
  • Как в Nuxt 3 использовать одну страницу для разных роутов?

    @null_object
    Динамические параметры во vue-router обозначаются через :

    export default defineNuxtConfig({
      hooks: {
        "pages:extend"(pages) {
          pages.push({
            name: "cities-id",
            path: "/cities/:id",
            file: "~/pages/cities.vue",
          });
        },
      },
    });

    Пример
    Ответ написан
    1 комментарий
  • Как правильно настроить refetch watch?

    @null_object
    <script setup lang="ts">
    import ModalDesktop from "~/components/modals/ModalDesktop.vue";
    
    interface Book {
      title: string;
      published_year: number;
      description: string;
      book_series: string;
      genre: string;
      authors: string;
      tag_id: string;
      id: string;
    }
    
    const token =
      "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIwY2Y5Nzk0Yi1jYjczLTR";
    
    const { data: books, refresh } = await useFetch<{ results: Book[] }>(
      "https://api.storage",
    );
    
    const { apiErrorHandler } = useErrorService();
    
    const selectedBook = ref<Book | null>(null);
    const showDeleteModal = ref(false);
    
    const modalVisible = computed(
      () => selectedBook.value !== null || showDeleteModal.value,
    );
    
    const openModal = (book: Book) => {
      selectedBook.value = book;
    };
    
    const closeModal = () => {
      selectedBook.value = null;
      showDeleteModal.value = false;
    };
    
    const deleteBook = async (book: Book) => {
      const { error } = await useFetch(`https://api.storage/${book.id}`, {
        method: "DELETE",
        headers: {
          Authorization: `Bearer ${token}`,
        },
      });
    
      if (error.value) {
        apiErrorHandler(error.value);
      } else {
        showDeleteModal.value = true;
        selectedBook.value = null;
      }
    };
    </script>


    <ModalDesktop v-if="modalVisible" @close="closeModal">
        <div class="px-space-s">
          <div v-if="selectedBook">
            <img
              :src="`https://api.storage/${selectedBook.cover_path}`"
              alt="Cover"
              class="w-[px] h-[100px] bg-center bg-cover"
            />
            <h4>{{ selectedBook.title }}</h4>
            <p><strong>Описание:</strong> {{ selectedBook.description }}</p>
            <p>
              <strong>Год публикации:</strong>
              {{ selectedBook.published_year }}
            </p>
            <p><strong>Серия:</strong> {{ selectedBook.book_series }}</p>
            <p><strong>Жанр:</strong> {{ selectedBook.genre }}</p>
            <p><strong>Автор:</strong> {{ selectedBook.authors }}</p>
            <p><strong>Тег:</strong> {{ selectedBook.tag_id }}</p>
            <p><strong>Id книги:</strong> {{ selectedBook.id }}</p>
          </div>
          <div v-if="showDeleteModal">
            <p>Книга успешно удалена!</p>
          </div>
          <div class="flex gap-x-space-s mt-space-s ml-auto">
            <button
              v-if="selectedBook"
              class="bg-blue-500 text-white p-space-xs pl-space-m pr-space-m rounded-medium hover:bg-blue-600"
              @click="deleteBook(selectedBook)"
            >
              Удалить
            </button>
          </div>
        </div>
      </ModalDesktop>
    Ответ написан