Skip to content

VTEX IO

Jose Luiz Rodrigues edited this page Sep 10, 2026 · 2 revisions

VTEX IO

palta nació de un problema concreto de VTEX IO: mostrar documentos, precios y medidas de América Latina sin arrastrar dependencias ni escribir la misma función de formateo en cada app.

Por qué encaja

restricción de VTEX IO cómo responde palta
El runtime de Node en IO es viejo el paquete declara engines: node >= 16 y la salida compilada no usa APIs nuevas
Las apps de IO castigan el peso del bundle cero dependencias en runtime, sideEffects: false, import por subpath
El catálogo entrega dimensiones en cm y peso en g measurements.format() auto-escala para mostrar sin tocar el dato
Un mismo componente sirve a varias tiendas de la región los 23 países tienen la misma forma de API

La CI corre en Node 22 y vitest 4 exige Node 20, pero eso es solo el toolchain de desarrollo. El paquete instala y corre en Node 16 igual.

Instalación en una app de IO

npm i @zeluizr/palta

Importá por subpath en apps de storefront, que es donde el peso importa:

import { cpf, currency } from '@zeluizr/palta/br'
import { length, weight } from '@zeluizr/palta/measurements'

Medidas de catálogo

VTEX manda siempre cm para dimensiones y g para peso. Mostrarlo crudo queda mal:

import { measurements } from '@zeluizr/palta'

// lo que llega del catálogo
const item = { height: 150, width: 50, length: 30, weight: 2500 }

measurements.length.format(item.height, 'cm')  // '1,50 m'
measurements.length.format(item.width, 'cm')   // '50 cm'
measurements.weight.format(item.weight, 'g')   // '2,50 kg'

El valor original no se toca: la escala pasa solo en la capa de presentación. Lo que mandás de vuelta a VTEX sigue en cm y g.

Documento en el checkout

import { cpf, cnpj } from '@zeluizr/palta/br'

function validarDocumento(valor: string, tipo: 'pf' | 'pj'): boolean {
  return tipo === 'pf' ? cpf.validate(valor) : cnpj.validate(valor)
}

Guardá siempre limpio en el orderForm y mostrá formateado en la interfaz:

const guardado = cpf.strip(input)     // '11144477735'
const mostrado = cpf.format(guardado) // '111.444.777-35'

Precios en una tienda multipaís

import * as palta from '@zeluizr/palta'

const monedaPorBinding = {
  'br.storefront': palta.br.currency,
  'cl.storefront': palta.cl.currency,
  'co.storefront': palta.co.currency,
} as const

function precio(binding: keyof typeof monedaPorBinding, monto: number): string {
  return monedaPorBinding[binding].format(monto)
}

Cada binding formatea con la convención de su país sin condicionales dispersos por los componentes.

Un componente de React reutilizable

import { useMemo } from 'react'
import * as palta from '@zeluizr/palta'

type Props = { pais: 'br' | 'cl' | 'ar'; monto: number }

export function Precio({ pais, monto }: Props) {
  const texto = useMemo(
    () => (Number.isFinite(monto) ? palta[pais].currency.format(monto) : '—'),
    [pais, monto],
  )

  return <span className="precio">{texto}</span>
}

Cosas para tener en cuenta

  • Brasil formatea teléfonos en nacional por defecto. Todos los demás países devuelven internacional. Si tu componente es genérico, pasá { international: true } explícitamente.
  • currency.format espera un número finito. Los precios de VTEX llegan en centavos como entero: dividí por 100 y verificá el resultado antes de formatear.
  • detect() no cubre los 23 países. En el checkout ya sabés el país del binding, así que llamá al módulo directo.
// precio de VTEX viene en centavos
const monto = item.sellingPrice / 100
const texto = Number.isFinite(monto) ? palta.br.currency.format(monto) : '—'

Ver también: Medidas, Recetas, Países.

Clone this wiki locally