ViteJS версии 5 не работает с Apexcharts

В настоящее время я работаю над проектом, использующим Ruby on Rails и React. Я использую Vite vite_rails и версию 5.3.1. Я пытаюсь интегрировать некоторые динамические диаграммы, используя примеры Apexcharts из Flowbite.

Как показано на изображении ниже, когда я запускаю vite dev и запускаю сервер, я вижу диаграмму. Но когда я запускаю vite build, кольцевая диаграмма, похоже, не компилируется.

Я не могу понять, почему. Я подозреваю, что должна быть проблема с настройкой конфигурации Vite.

vite.config.mjs

import { defineConfig } from 'vite';
import RubyPlugin from 'vite-plugin-ruby';
import svgr from 'vite-plugin-svgr';

export default defineConfig({
  plugins: [
    RubyPlugin(),
    svgr({
      svgrOptions: {
        exportType: 'named',
        ref: true,
        svgo: false,
        titleProp: true,
      },
      include: '**/*.svg',
    }),
    muteWarningsPlugin(warningsToIgnore),
  ],
  build: {
    minify: false,
    terserOptions: {
      compress: {
        keep_infinity: true,
        drop_console: false, // Keep console.info() statements
      },
    },
    sourcemap: true, // Ensure sourcemaps are enabled
  },
});

Основываясь на этом примере, я устанавливаю кольцевую диаграмму от Flowbite.

DonutChart.jsx

import React, { useEffect, useRef, useState } from 'react';
import ApexCharts from 'apexcharts';
import LoadingSpinner from './LoadingSpinner';

const DonutChart = () => {
  const chartRef = useRef(null);
  const [series, setSeries] = useState([0, 0, 0]);
  const [loading, setLoading] = useState(true);

  const getChartOptions = (stats) => {
    return {
      series: series,
      colors: ["#022963", "#e74694", "#FDBA8C"],
      chart: {
        height: 320,
        width: "100%",
        type: "donut",
      },
      stroke: {
        colors: ["transparent"],
        lineCap: "",
      },
      plotOptions: {
        pie: {
          donut: {
            labels: {
              show: true,
              name: {
                show: true,
                fontFamily: "Inter, sans-serif",
                offsetY: 20,
              },
              total: {
                showAlways: true,
                show: true,
                label: "Total Assets",
                fontFamily: "Inter, sans-serif",
                formatter: function () {
                  return stats.total_assets;
                },
              },
              value: {
                show: true,
                fontFamily: "Inter, sans-serif",
                fontWeight: 'bold',
                offsetY: -20,
                formatter: function (value) {
                  return value + "%"
                },
              },
            },
            size: "80%",
          },
        },
      },
      grid: {
        padding: {
          top: -2,
        },
      },
      labels: ["Operational", "Not Operational", "Under repair"],
      dataLabels: {
        enabled: false,
      },
      legend: {
        position: "bottom",
        fontFamily: "Inter, sans-serif",
      },
      yaxis: {
        labels: {
          formatter: function (value) {
            return value + "%"
          },
        },
      },
      xaxis: {
        labels: {
          formatter: function (value) {
            return value + "%"
          },
        },
        axisTicks: {
          show: false,
        },
        axisBorder: {
          show: false,
        },
      },
    }
  }

  useEffect(() => {
    let chartInstance = null;

    const fetchData = async () => {
      try {
        const response = await fetch('/api/v1/equipment_stats');
        const stats = await response.json();

        const newSeries = [
          stats.operational || 0,
          stats.not_operational || 0,
          stats.under_repair || 0,
        ];

        setSeries(newSeries);
        setLoading(false);

        if (!chartInstance && chartRef.current) {
          const chartOptions = getChartOptions(stats);
          chartOptions.series = newSeries.filter(n => n !== null && n !== undefined); // Ensure no null/undefined values
          chartInstance = new ApexCharts(chartRef.current, chartOptions);
          chartInstance.render();
        } else if (chartInstance) {
          chartInstance.updateSeries(newSeries);
        }
      } catch (error) {
        console.error("Error fetching data:", error);
        setLoading(false);
        // Optionally, handle the UI here for error state
      }
    };

    fetchData();

    return () => {
      if (chartInstance) {
        chartInstance.destroy();
      }
    };
  }, []);


  if (loading) {
    return <LoadingSpinner />;
  }

  return (
    <div className = "py-4">
      <h2 className = "text-center font-semibold my-4">Equipment Health</h2>
      <div ref = {chartRef}></div>
    </div>
  );
}

export default DonutChart;

вот другая соответствующая информация

пакет.json

{
  "name": "aviato",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "serve": "vite preview"
  },
  "dependencies": {
    "@emotion/react": "^11.11.3",
    "@emotion/styled": "^11.11.0",
    "@headlessui/react": "^1.7.15",
    "@heroicons/react": "^2.0.18",
    "@mui/icons-material": "^5.15.10",
    "@mui/material": "^5.15.10",
    "@rails/activestorage": "^7.0.6",
    "@stripe/react-stripe-js": "^2.4.0",
    "@stripe/stripe-js": "^2.4.0",
    "@tailwindcss/forms": "^0.5.3",
    "activestorage": "^5.2.8-1",
    "apexcharts": "^3.44.0",
    "clsx": "^2.1.0",
    "crypto-js": "^4.2.0",
    "react": "^18.2.0",
    "react-currency-input-field": "^3.6.11",
    "react-dom": "^18.2.0",
    "react-hook-form": "^7.48.2",
    "react-router-dom": "^6.14.0",
    "tailwindcss": "^3.3.2"
  },
  "devDependencies": {
    "autoprefixer": "^10.4.14",
    "postcss": "^8.4.24",
    "tailwindcss": "^3.3.2",
    "vite": "^5.3.1",
    "vite-plugin-ruby": "^5.0.0",
    "vite-plugin-svgr": "^4.2.0"
  },
  "volta": {
    "node": "20.10.0"
  }
}

Это ошибка, с которой я боролся пару недель. Я поднял этот вопрос перед командой Vite. https://github.com/vitejs/vite/issues/17516

Gemfile.lock

    vite_rails (3.0.17)
      railties (>= 5.1, < 8)
      vite_ruby (~> 3.0, >= 3.2.2)

Я вижу, что проблема в том, что запрос на получение выполнен для Started GET "/application-BjlQHfxw.js.map" for ::1 at 2024-06-19 13:30:17 -0500 ActionController::RoutingError (No route matches [GET] "/application-BjlQHfxw.js.map"):, но компилируемый JS находится в /vite/assets/application-. как мне настроить этот путь?

Steven Aguilar 19.06.2024 20:42

Возможно, на содержащем сайте действует политика безопасности контента (проверьте заголовки ответов CSP в HTTP-запросе, чтобы получить всю страницу), и библиотека, возможно, нарушает ее. О таких нарушениях будет сообщено в консоли инструментов разработчика.

adsy 20.06.2024 00:18

Это был рискованный шаг, но, тем не менее, можно было ожидать ошибки в инструментах разработки браузера. Требование .map предназначено для исходных карт и не должно иметь особого значения, если оно вообще не работает.

adsy 20.06.2024 00:19
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
3
62
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не уверен, как ваш пример работает при запуске vite dev. Я попробовал это на более простом примере, чтобы запустить его, но в любом случае это не сработало. У вас есть состояние гонки между вызовом useEffect и установкой chartRef.current.

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

https://react.dev/reference/react/useEffect#parameters

Если вы зарегистрируете chartRef.current, это будет null на первом рендере. Чтобы эта настройка работала, вы должны где-то запустить повторный рендеринг.

Мне было достаточно объявить loading как зависимость:

useEffect(() => {
  let chartInstance = null;
  setLoading(false);

  console.info(chartRef); // initial:  {current: null}
                         // rerender: {current: div}

  if (!chartInstance && chartRef.current) {
    chartInstance = new ApexCharts(chartRef.current, getChartOptions({}));
    chartInstance.render();
  }

  return () => {
    if (chartInstance) {
      chartInstance.destroy();
    }
  };
}, [loading]);
//  ^^^^^^^

Другие вопросы по теме