Cómo crear archivos Excel en JavaScript (XLSX/XLS)

2026-09-30 01:34:14 Allen Yang
AI Summarize:
ChatGPT
ChatGPT ✓
Claude ✓
Grok ✓
Perplexity ✓
Quick
Quick
Concise overview
Highlights
Key takeaways
Detailed
Structured explanation
Brief
One sentence summary
Summarize |

Create Excel files in JavaScript with Spire.XLS — browser to XLSX and XLS

JavaScript puede generar libros de Excel directamente en el navegador. Con Spire.XLS for JavaScript, puede crear un libro, agregar hojas de cálculo, escribir valores y fórmulas, aplicar formato y guardar el resultado como un archivo XLSX o XLS, todo del lado del cliente, sin necesidad de instalar Microsoft Excel.

Este tutorial comienza con un libro XLSX básico y luego agrega valores de celda con tipo, fórmulas, formato, varias hojas de cálculo, compatibilidad de descarga en el navegador, conversión de CSV y salida XLS para compatibilidad heredada.

Instalar e inicializar Spire.XLS for JavaScript

Spire.XLS for JavaScript se distribuye dentro del paquete spire.office, junto con Spire.PDF, Spire.Doc y Spire.Presentation:

npm i spire.office

Iniciar el tiempo de ejecución requiere dos importaciones. La primera inicia el host compartido de .NET WebAssembly; la segunda registra la API de hojas de cálculo:

// 1. Boot the shared runtime once per page.
const common = await import('/node_modules/spire.office/spire.common.js');
await common.initializeWasm();

// 2. Load the spreadsheet engine — this is what creates window.spirexls.
await import('/node_modules/spire.office/spire.xls.js');

Los archivos Spire.*.Wasm.zip y la carpeta _framework deben ser accesibles desde la raíz del sitio. El tiempo de ejecución los resuelve contra la URL del documento en lugar de contra el módulo que realizó la importación, por lo que en un proyecto de Vite o Create React App deben ubicarse en public/. El prefijo process.env.PUBLIC_URL que se muestra en configuraciones basadas en React es una convención de Create React App, no un estándar del navegador; ajuste la ruta base para que coincida con su herramienta de compilación si no está usando CRA. Si faltan los archivos, el navegador registra WebAssembly.compile(): expected magic word; el servidor de desarrollo ha respondido a la solicitud del archivo con index.html.

Luego, todo depende de una única variable global:

const xls = window.spirexls;

En la configuración actual del paquete utilizada por este tutorial, la API de hojas de cálculo se expone a través de window.spirexls. Use esa variable global después de que se haya inicializado el tiempo de ejecución. Las versiones anteriores la exponían como window.wasmModule.spirexls; si está trabajando con una versión diferente del paquete, verifique qué variable global está disponible.

Ya está listo para generar archivos de Excel.

Crear un archivo de Excel básico en JavaScript

Vamos a crear un informe de ventas. Crearemos un libro, agregaremos una hoja de cálculo, escribiremos datos de productos en las celdas y guardaremos el resultado como un archivo XLSX que se descarga automáticamente.

async function createExcelFile() {
    const xls = window.spirexls;
    if (!xls) {
        console.error('Spire.XLS is not initialized.');
        return;
    }

    // A fresh Workbook() already contains three blank worksheets, so clear them
    // and add the single sheet this report needs.
    const workbook = new xls.Workbook();
    workbook.Worksheets.Clear();
    const sheet = workbook.Worksheets.Add("Sales Report");

    // Sample data: product sales
    const data = [
        ["Product", "Quantity", "Price"],
        ["Laptop", 10, 999.99],
        ["Mouse", 50, 24.99],
        ["Keyboard", 30, 59.99],
        ["Monitor", 15, 329.99]
    ];

    // Write data to cells
    for (let row = 0; row < data.length; row++) {
        for (let col = 0; col < data[row].length; col++) {
            const cell = sheet.Range.get({ row: row + 1, column: col + 1 });
            if (typeof data[row][col] === "string") {
                cell.Text = data[row][col];
            } else {
                cell.NumberValue = data[row][col];
            }
        }
    }

    // Save to the virtual file system, read the bytes, download, then dispose
    const fileName = "SalesReport.xlsx";
    workbook.SaveToFile({
        fileName: fileName,
        version: xls.ExcelVersion.Version2016
    });

    const fileData = window.dotnetRuntime.Module.FS.readFile(fileName);
    const blob = new Blob([fileData], {
        type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = fileName;
    a.click();
    URL.revokeObjectURL(url);

    workbook.Dispose();
}

Llame a createExcelFile() y obtendrá un SalesReport.xlsx con cuatro filas de productos más un encabezado. El flujo de trabajo es simple: crear libro → escribir datos → guardar → descargar.

Las siguientes secciones amplían este ejemplo. Cada fragmento de código supone que se agrega dentro de createExcelFile() después de que se hayan creado el libro y la hoja de cálculo.

SalesReport.xlsx generated by the basic createExcelFile() function

Escribir diferentes tipos de datos en celdas de Excel

Excel distingue entre texto, números, fechas y valores booleanos. Equivocarse con esto genera archivos en los que la ordenación se rompe, las fórmulas devuelven errores y los números se muestran como texto.

const sheet = workbook.Worksheets.get(0);

// Text — for labels, names, descriptions
sheet.Range.get("A1").Text = "Product Name";

// Number — for anything you'll calculate, sort, or filter
sheet.Range.get("B1").NumberValue = 999.99;

// Date — a real DateTimeValue plus a display format
const dateCell = sheet.Range.get("C1");
dateCell.DateTimeValue = new Date(Date.UTC(2025, 2, 15));
dateCell.NumberFormat = "yyyy-mm-dd";

// Boolean — use BooleanValue, not text
sheet.Range.get("D1").BooleanValue = true;

¿El error más común? Escribir cell.Text = "999.99" en lugar de cell.NumberValue = 999.99. El valor se ve idéntico al abrir el archivo, pero Excel lo trata como texto: no puede sumarlo, promediarlo ni ordenarlo numéricamente. Use siempre NumberValue para números, DateTimeValue para fechas y BooleanValue para booleanos.

Las fechas necesitan una precaución adicional. DateTimeValue conserva el instante UTC representado por el Date de JavaScript. Por lo tanto, crear una fecha con la medianoche local puede desplazar el día mostrado en algunas zonas horarias; use Date.UTC() cuando desee que se conserve una fecha de calendario específica.

Agregar fórmulas a la hoja de cálculo de Excel

Las fórmulas convierten su archivo generado en una hoja de cálculo real, no solo en un volcado de datos. Agreguemos una columna Total que calcule Quantity × Price para cada fila, más un total general en la parte inferior:

// Add "Total" header
sheet.Range.get({ row: 1, column: 4 }).Text = "Total";

// Per-row formula: Total = Quantity × Price
for (let i = 2; i <= 5; i++) {
    sheet.Range.get({ row: i, column: 4 }).Formula = `=B${i}*C${i}`;
}

// Grand total row
sheet.Range.get({ row: 6, column: 1 }).Text = "Total";
sheet.Range.get({ row: 6, column: 2 }).Formula = "=SUM(B2:B5)";
sheet.Range.get({ row: 6, column: 4 }).Formula = "=SUM(D2:D5)";

// Evaluate the formulas once, so their results are written into the file.
workbook.CalculateAllValue();

Llame a workbook.CalculateAllValue() antes de guardar cuando necesite que el libro generado contenga resultados de fórmulas calculados. Esto es útil para visores o aplicaciones que dependen de valores en caché en lugar de recalcular las fórmulas al abrir.

Para obtener una guía completa sobre funciones de Excel y operaciones con fórmulas, consulte Insertar o leer funciones y fórmulas en hojas de cálculo de Excel con JavaScript en React.

Formatear el archivo de Excel generado

Una hoja de cálculo con datos sin procesar funciona, pero una hoja de cálculo con formato comunica. Convirtamos nuestro informe de ventas en algo que realmente enviaría a una parte interesada:

// Bold, colored header row
const header = sheet.Range.get("A1:D1");
header.Style.Font.IsBold = true;
header.Style.Font.Size = 12;
header.Style.Color = xls.Color.get_LightSkyBlue();

// Currency format for Price and Total columns
for (let i = 2; i <= 5; i++) {
    sheet.Range.get({ row: i, column: 3 }).NumberFormat = "$#,##0.00";
    sheet.Range.get({ row: i, column: 4 }).NumberFormat = "$#,##0.00";
}

// Set column widths explicitly
[26, 10, 12, 12].forEach((width, i) => {
    sheet.Columns.get(i).ColumnWidth = width;
});

// Clean borders
const usedRange = sheet.Range.get("A1:D6");
usedRange.Borders.LineStyle = xls.LineStyleType.Thin;
usedRange.Borders.Color = xls.Color.get_LightSteelBlue();

Vale la pena conocer dos detalles aquí. sheet.Columns.get(i) y sheet.Rows.get(i) están basados en 0 y usan get, a diferencia del get_Item que exponen otras colecciones. Y en la configuración del navegador probada, AutoFitColumn requiere una fuente que no está disponible en el entorno aislado de WebAssembly, por lo que establecer ColumnWidth explícitamente es más confiable.

El resultado: un encabezado azul en negrita, precios con formato de moneda, columnas con el tamaño adecuado y bordes limpios.

Para obtener una guía detallada sobre las dimensiones de filas y columnas, consulte Establecer la altura de fila y el ancho de columna en Excel con JavaScript en React.

Crear varias hojas de cálculo en un libro de Excel

Los informes reales rara vez caben en una sola hoja. Un informe de ventas podría tener un resumen en la primera pestaña, detalles de productos en la segunda y desgloses mensuales en la tercera.

workbook.Worksheets.Clear();
const summarySheet = workbook.Worksheets.Add("Summary");
const productsSheet = workbook.Worksheets.Add("Products");
const monthlySheet = workbook.Worksheets.Add("Monthly Data");

// Products sheet — write actual data so cross-sheet formulas work
productsSheet.Range.get("A1").Text = "Product";
productsSheet.Range.get("B1").Text = "Quantity";
productsSheet.Range.get("C1").Text = "Price";
productsSheet.Range.get("D1").Text = "Total";

const products = [
    ["Laptop", 10, 999.99],
    ["Mouse", 50, 24.99],
    ["Keyboard", 30, 59.99],
    ["Monitor", 15, 329.99]
];

for (let i = 0; i < products.length; i++) {
    const row = i + 2;
    productsSheet.Range.get({ row: row, column: 1 }).Text = products[i][0];
    productsSheet.Range.get({ row: row, column: 2 }).NumberValue = products[i][1];
    productsSheet.Range.get({ row: row, column: 3 }).NumberValue = products[i][2];
    productsSheet.Range.get({ row: row, column: 4 }).Formula = `=B${row}*C${row}`;
}

// Summary sheet with cross-sheet reference
summarySheet.Range.get("A1").Text = "Sales Summary";
summarySheet.Range.get("A1").Style.Font.IsBold = true;
summarySheet.Range.get("A2").Text = "Total Products";
summarySheet.Range.get("B2").NumberValue = 4;
summarySheet.Range.get("A3").Text = "Total Revenue";
summarySheet.Range.get("B3").Formula = "=SUM(Products!D2:D5)";

Cada Worksheets.Add(name) devuelve la hoja que acaba de crear, en el orden en que se realizan las llamadas, por lo que el orden de las pestañas coincide con el orden del código. Observe la fórmula entre hojas: =SUM(Products!D2:D5) en la hoja Summary hace referencia a la columna Total de la hoja Products. Excel lo maneja automáticamente cuando se abre el archivo; no se necesita código adicional.

Multi-sheet workbook with Summary and Products tabs

Para obtener más información sobre la administración de hojas de cálculo (agregar, eliminar y reordenar hojas), consulte Agregar, eliminar y mover hojas de cálculo de Excel con JavaScript en React.

Guardar y descargar el archivo XLSX en el navegador

Una vez que su libro esté listo, Spire.XLS lo guarda en un sistema de archivos virtual de WebAssembly. Luego lee los datos del archivo, los convierte en un Blob y activa una descarga:

workbook.SaveToFile({
    fileName: "Report.xlsx",
    version: xls.ExcelVersion.Version2016
});

const fileData = window.dotnetRuntime.Module.FS.readFile("Report.xlsx");
const blob = new Blob([fileData], {
    type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
});
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "Report.xlsx";
a.click();
URL.revokeObjectURL(url);

workbook.Dispose();

Llame siempre a workbook.Dispose() después de la descarga para liberar memoria, especialmente en aplicaciones donde los usuarios generan varios archivos en una sesión. El libro en sí reside en el montón de WebAssembly hasta que lo haga, y el recolector de basura del navegador no reclama ese montón.

¿Busca integración con React o exportación de tablas HTML? Consulte nuestra guía para descargar y exportar archivos de Excel en JavaScript y React.

Integrarlo todo: un informe de ventas con formato

Los fragmentos anteriores construyen un libro una preocupación a la vez. Aquí están en una sola función: una hoja de cálculo con estilo, con bandas de cebra y formatos de moneda, columnas de ingresos y participación impulsadas por fórmulas, un gráfico de columnas y una segunda hoja de cálculo que consolida los números.

/**
 * Build a formatted sales report workbook in the browser and download it as
 * SalesReport.xlsx.
 *
 * The layout is driven by `products` below — swap it for form input, an API
 * response or component state and nothing else needs to change.
 */
async function createExcelReport() {
  // spire.office 11.7.0 exposes Spire.XLS as `window.spirexls`. Older builds
  // hung it off `window.wasmModule.spirexls`; that global no longer exists.
  const xls = window.spirexls;
  if (!xls) throw new Error('Spire.XLS is not ready yet');

  // [product, units sold, unit price] — revenue and share are derived by formula
  const products = [
    ['Atlas 14 Ultrabook', 42, 1249.0],
    ['Orbit Wireless Mouse', 380, 24.99],
    ['Vertex Mechanical Keyboard', 165, 89.5],
    ['Lumen 27 4K Monitor', 74, 429.0],
    ['Halo USB-C Dock', 210, 139.0],
    ['Pulse ANC Headset', 128, 199.0],
  ];
  const FIRST = 5; // first data row
  const TOTAL = FIRST + products.length; // total row

  const wb = new xls.Workbook();
  wb.Worksheets.Clear();
  const sheet = wb.Worksheets.Add('Sales Report');

  const at = (a) => sheet.Range.get(a);
  const cell = (row, col) => sheet.Range.get({ row: row, column: col });
  const paint = (a, colour) => {
    at(a).Style.Color = colour;
  };

  // ── Sizing ── explicit widths (AutoFitColumn is unreliable in the WASM sandbox)
  [34, 9, 13, 14, 9].forEach((w, i) => {
    sheet.Columns.get(i).ColumnWidth = w;
  });
  sheet.Rows.get(0).RowHeight = 34; // title
  sheet.Rows.get(1).RowHeight = 20; // subtitle
  sheet.Rows.get(2).RowHeight = 8; // spacer
  sheet.Rows.get(3).RowHeight = 24; // header

  // ── Title band ── merge first, then style the whole merged area
  at('A1:E1').Merge();
  cell(1, 1).Text = 'Sales Report — Q3 2026';
  paint('A1:E1', xls.Color.get_DarkBlue());
  at('A1:E1').Style.Font.Color = xls.Color.get_White();
  at('A1:E1').Style.Font.IsBold = true;
  at('A1:E1').Style.Font.Size = 15;
  at('A1:E1').Style.VerticalAlignment = xls.VerticalAlignType.Center;

  at('A2:E2').Merge();
  cell(2, 1).Text = 'Region: West · Period: 1 Jul – 30 Sep 2026 · Amounts in USD';
  paint('A2:E2', xls.Color.get_DarkBlue());
  at('A2:E2').Style.Font.Color = xls.Color.get_LightSteelBlue();
  at('A2:E2').Style.Font.Size = 9.5;
  at('A2:E2').Style.VerticalAlignment = xls.VerticalAlignType.Center;

  // ── Header row ───────────────────────────────────────────────────────────
  ['Product', 'Units', 'Unit Price', 'Revenue', 'Share'].forEach((label, i) => {
    cell(4, i + 1).Text = label;
  });
  paint('A4:E4', xls.Color.get_LightSteelBlue());
  at('A4:E4').Style.Font.Color = xls.Color.get_DarkBlue();
  at('A4:E4').Style.Font.IsBold = true;
  at('A4:E4').Style.Font.Size = 10.5;
  at('A4:E4').Style.HorizontalAlignment = xls.HorizontalAlignType.Center;
  at('A4:E4').Style.VerticalAlignment = xls.VerticalAlignType.Center;

  // ── Data rows ── numbers go in as NumberValue, never as text
  products.forEach(([name, units, price], i) => {
    const r = FIRST + i;
    cell(r, 1).Text = name;
    cell(r, 2).NumberValue = units;
    cell(r, 3).NumberValue = price;
    cell(r, 4).Formula = `=B${r}*C${r}`;
    cell(r, 5).Formula = `=D${r}/$D${TOTAL}`; // share of the grand total
    sheet.Rows.get(r - 1).RowHeight = 20;
    if (i % 2) paint(`A${r}:E${r}`, xls.Color.get_WhiteSmoke()); // zebra banding
  });

  // ── Total row ────────────────────────────────────────────────────────────
  cell(TOTAL, 1).Text = 'Total';
  [2, 4, 5].forEach((col) => {
    const letter = String.fromCharCode(64 + col);
    cell(TOTAL, col).Formula = `=SUM(${letter}${FIRST}:${letter}${TOTAL - 1})`;
  });
  paint(`A${TOTAL}:E${TOTAL}`, xls.Color.get_LightSkyBlue());
  at(`A${TOTAL}:E${TOTAL}`).Style.Font.IsBold = true;
  sheet.Rows.get(TOTAL - 1).RowHeight = 22;

  // ── Number formats and borders ───────────────────────────────────────────
  at(`B${FIRST}:B${TOTAL}`).NumberFormat = '#,##0';
  at(`C${FIRST}:D${TOTAL}`).NumberFormat = '$#,##0.00';
  at(`E${FIRST}:E${TOTAL}`).NumberFormat = '0.0%';

  const table = at(`A4:E${TOTAL}`);
  table.Borders.LineStyle = xls.LineStyleType.Thin;
  table.Borders.Color = xls.Color.get_LightSteelBlue();
  at(`A${TOTAL}:E${TOTAL}`).Borders.get_Item(xls.BordersLineType.EdgeTop).LineStyle =
    xls.LineStyleType.Medium;

  // ── Chart ── build the series by hand (DataRange would mix units)
  const chart = sheet.Charts.Add();
  chart.ChartType = xls.ExcelChartType.ColumnClustered;
  chart.LeftColumn = 6;
  chart.TopRow = 3;
  chart.RightColumn = 13;
  chart.BottomRow = 21;
  const serie = chart.Series.Add();
  serie.CategoryLabels = at(`A${FIRST}:A${TOTAL - 1}`);
  serie.Values = at(`D${FIRST}:D${TOTAL - 1}`);
  serie.Name = 'Revenue';
  chart.ChartTitleArea.Text = 'Revenue by product';
  chart.HasLegend = false;
  chart.PrimaryValueAxis.NumberFormat = '$#,##0';

  // ── Sheet chrome ──
  sheet.FreezePanes(FIRST, 1);
  sheet.GridLinesVisible = false;
  sheet.TabColor = xls.Color.get_DarkBlue();

  // ── Second worksheet: cross-sheet roll-up ──
  const summary = wb.Worksheets.Add('Summary');
  summary.Columns.get(0).ColumnWidth = 26;
  summary.Columns.get(1).ColumnWidth = 18;
  summary.Rows.get(0).RowHeight = 30;
  summary.Rows.get(1).RowHeight = 18;
  summary.Rows.get(3).RowHeight = 22;

  const band = (a, text, size) => {
    summary.Range.get(a).Merge();
    summary.Range.get(a.split(':')[0]).Text = text;
    summary.Range.get(a).Style.Color = xls.Color.get_DarkBlue();
    summary.Range.get(a).Style.Font.Color = xls.Color.get_White();
    summary.Range.get(a).Style.Font.IsBold = true;
    summary.Range.get(a).Style.Font.Size = size;
    summary.Range.get(a).Style.VerticalAlignment = xls.VerticalAlignType.Center;
  };
  band('A1:B1', 'Executive Summary', 14);
  band('A2:B2', 'Sales Report · Q3 2026', 9.5);

  ['Metric', 'Value'].forEach((label, i) => {
    summary.Range.get({ row: 4, column: i + 1 }).Text = label;
  });
  summary.Range.get('A4:B4').Style.Color = xls.Color.get_LightSteelBlue();
  summary.Range.get('A4:B4').Style.Font.Color = xls.Color.get_DarkBlue();
  summary.Range.get('A4:B4').Style.Font.IsBold = true;

  [
    ['Total revenue', "='Sales Report'!D" + TOTAL, '$#,##0.00'],
    ['Units shipped', "='Sales Report'!B" + TOTAL, '#,##0'],
    ['Average unit price', `='Sales Report'!D${TOTAL}/'Sales Report'!B${TOTAL}`, '$#,##0.00'],
  ].forEach(([label, formula, format], i) => {
    summary.Range.get({ row: 5 + i, column: 1 }).Text = label;
    const value = summary.Range.get({ row: 5 + i, column: 2 });
    value.Formula = formula;
    value.NumberFormat = format;
    value.Style.HorizontalAlignment = xls.HorizontalAlignType.Right;
    if (i % 2) summary.Range.get(`A${5 + i}:B${5 + i}`).Style.Color = xls.Color.get_WhiteSmoke();
  });

  // Date — use Date.UTC to avoid timezone shift
  summary.Range.get('A8').Text = 'Report date';
  const reportDate = summary.Range.get('B8');
  reportDate.DateTimeValue = new Date(Date.UTC(2026, 8, 28));
  reportDate.NumberFormat = 'yyyy-mm-dd';
  reportDate.Style.HorizontalAlignment = xls.HorizontalAlignType.Right;

  const kpis = summary.Range.get('A4:B8');
  kpis.Borders.LineStyle = xls.LineStyleType.Thin;
  kpis.Borders.Color = xls.Color.get_LightSteelBlue();
  summary.GridLinesVisible = false;
  summary.TabColor = xls.Color.get_LightSteelBlue();

  // ── Save, then release ──
  wb.CalculateAllValue();
  const fileName = 'SalesReport.xlsx';
  wb.SaveToFile({ fileName: fileName, version: xls.ExcelVersion.Version2016 });

  const fileData = window.dotnetRuntime.Module.FS.readFile(fileName);
  const blob = new Blob([fileData], {
    type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  });
  const url = URL.createObjectURL(blob);
  Object.assign(document.createElement('a'), { href: url, download: fileName }).click();
  URL.revokeObjectURL(url);

  wb.Dispose(); // free the WASM heap — one workbook per generation cycle
}

El diseño sigue los datos. Reemplace el array products con una respuesta de su propia API y todo lo demás (totales, porcentajes de participación, el rango del gráfico, la consolidación del resumen) seguirá funcionando, porque todo está expresado como fórmulas o rangos derivados en lugar de valores codificados de forma fija.

Complete formatted sales report with chart, zebra banding, and summary worksheet

Para obtener más tipos de gráficos y opciones de configuración, consulte Crear gráficos de Excel con JavaScript en React.

Crear un archivo de Excel a partir de datos CSV

Puede cargar datos tabulares desde un archivo CSV en una hoja de cálculo y guardar el resultado como XLSX. El libro resultante se puede formatear o ampliar con fórmulas y hojas de cálculo adicionales:

// The library reads from its own virtual file system, so the CSV has to be
// there before you can load it — written from a string here, from the bytes of
// a File object in a real application.
const csv = "Product,Quantity,Price\nLaptop,10,999.99\nMouse,50,24.99\nKeyboard,30,59.99";
window.dotnetRuntime.Module.FS.writeFile("data.csv", new TextEncoder().encode(csv));

workbook.LoadFromFile("data.csv", ",");
workbook.SaveToFile({
    fileName: "ConvertedFromCSV.xlsx",
    version: xls.ExcelVersion.Version2016
});

La hoja importada recibe el nombre del archivo (data), por lo que Worksheets.get(0) la toma.

El separador es un segundo argumento obligatorio. LoadFromFile("data.csv") por sí solo se rechaza con This is not a structured storage file, porque la sobrecarga de un solo argumento espera un formato estructurado como .xlsx o .xls y no detecta CSV.

Hay un segundo problema: el importador de CSV escribe todos los campos como texto. Una columna de cantidad llega como "10" en lugar de 10, lo que significa que no se puede sumar ni ordenar numéricamente, el problema exacto descrito anteriormente en este tutorial. Convierta las columnas que necesite antes de guardar:

const csvSheet = workbook.Worksheets.get(0);

// The importer leaves every field as text — coerce each numeric column.
// Columns 2 and 3 hold Quantity and Price; both arrive as "10" and "999.99".
for (let row = 2; row <= 4; row++) {
    [2, 3].forEach((column) => {
        const cell = csvSheet.Range.get({ row: row, column: column });
        if (cell.Text !== "") {
            cell.NumberValue = Number(cell.Text);
        }
    });
}

Para obtener una guía completa sobre la conversión entre formatos CSV y Excel, consulte nuestro tutorial de conversión de CSV a Excel.

Crear un archivo XLS en lugar de XLSX

Si su aplicación necesita generar el formato .xls heredado en lugar de .xlsx, cambie el parámetro de versión:

workbook.SaveToFile({
    fileName: "Report.xls",
    version: xls.ExcelVersion.Version97to2003
});

El miembro de enumeración es Version97to2003; no existe Version97. Mantenga los gráficos en XLSX; el escritor XLS probado falla cuando se requieren métricas de fuente de gráficos.

XLSX (Excel 2007+) es el formato recomendado para aplicaciones nuevas. XLS (Excel 97–2003) solo es necesario cuando se requiere compatibilidad con versiones anteriores.

Problemas comunes

window.wasmModule no está definido. Los ejemplos más antiguos leían la API de hojas de cálculo desde window.wasmModule.spirexls. Las versiones actuales la instalan directamente en window.spirexls y dejan wasmModule sin definir, por lo que el primer acceso genera un error. En su lugar, verifique window.spirexls.

Módulo WASM no inicializado. Si window.spirexls no está definido, el tiempo de ejecución no ha terminado de cargarse. Muestre un indicador de carga y espere a que se complete la inicialización antes de intentar cualquier operación de Excel.

El ajuste automático genera un error de fuente. AutoFitColumn y AutoFitRow necesitan una fuente del sistema para medir el texto, y el entorno aislado de WebAssembly no tiene ninguna. Fallan con Cannot found font(Arial) installed on the system. Calcule o codifique de forma fija los anchos de sus columnas con sheet.Columns.get(i).ColumnWidth.

Números almacenados como texto. Usar cell.Text = "100" en lugar de cell.NumberValue = 100 rompe la ordenación y los cálculos. Este es el problema más común que encuentran los desarrolladores al escribir archivos de Excel en JavaScript, y la importación de CSV lo provoca automáticamente; use siempre NumberValue para datos numéricos.

Aparece una hoja de "Advertencia de evaluación". Cuando se usa la compilación de evaluación sin una licencia válida, Spire.XLS agrega una hoja de evaluación al libro guardado. Esta hoja se vuelve a crear al guardar, por lo que eliminarla mediante programación no es una solución confiable. Aplique una clave de licencia para evitarlo.

Fugas de memoria en aplicaciones de larga duración. Llame a workbook.Dispose() después de cada ciclo de generación. En aplicaciones de una sola página, los libros no eliminados acumulan memoria y degradan el rendimiento con el tiempo.

Preguntas frecuentes

¿Puede JavaScript crear archivos de Excel sin Microsoft Excel?

Sí. Spire.XLS for JavaScript se ejecuta completamente en el navegador mediante WebAssembly. No se requiere Microsoft Excel ni una instalación de Office del lado del servidor para generar archivos XLSX.

¿Puede JavaScript crear archivos XLSX directamente en el navegador?

Sí. Todas las operaciones de hojas de cálculo ocurren del lado del cliente. El archivo se guarda en un sistema de archivos virtual y luego se descarga como un Blob; no se necesita un servidor backend.

¿Cuál es la diferencia entre XLS y XLSX?

XLSX (Excel 2007 y posteriores) es el formato moderno basado en XML, recomendado para aplicaciones nuevas. XLS (Excel 97–2003) es el formato binario heredado, útil para la compatibilidad con sistemas más antiguos.

Conclusión

Crear archivos de Excel en JavaScript no requiere un servidor backend ni Microsoft Excel. Con Spire.XLS for JavaScript, puede crear libros desde cero, escribir datos con tipo, agregar fórmulas, aplicar formato y organizar datos en varias hojas, todo en el navegador.

Comience con el ejemplo básico anterior y luego agregue fórmulas y formato a medida que crezcan sus necesidades. Para obtener integración específica de React y exportación de tablas HTML, consulte nuestro tutorial dedicado a la exportación.

Ver también