В настоящее время я работаю над проектом, использующим Ruby on Rails и React. Я использую Vite vite_rails и версию 5.3.1. Я пытаюсь интегрировать некоторые динамические диаграммы, используя примеры Apexcharts из Flowbite.
Как показано на изображении ниже, когда я запускаю vite dev
и запускаю сервер, я вижу диаграмму. Но когда я запускаю vite build
, кольцевая диаграмма, похоже, не компилируется.
Я не могу понять, почему. Я подозреваю, что должна быть проблема с настройкой конфигурации Vite.
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.
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;
вот другая соответствующая информация
{
"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
vite_rails (3.0.17)
railties (>= 5.1, < 8)
vite_ruby (~> 3.0, >= 3.2.2)
Возможно, на содержащем сайте действует политика безопасности контента (проверьте заголовки ответов CSP в HTTP-запросе, чтобы получить всю страницу), и библиотека, возможно, нарушает ее. О таких нарушениях будет сообщено в консоли инструментов разработчика.
Это был рискованный шаг, но, тем не менее, можно было ожидать ошибки в инструментах разработки браузера. Требование .map
предназначено для исходных карт и не должно иметь особого значения, если оно вообще не работает.
Я не уверен, как ваш пример работает при запуске 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]);
// ^^^^^^^
Я вижу, что проблема в том, что запрос на получение выполнен для
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-.
как мне настроить этот путь?