Leodario.com

Leodario.com – Tudo sobre Tecnologia

Aula 77 – Loja Shopify do Zero ao Avançado: Shopify Functions e extensibilidade avançada

Imagem destacada da aula Shopify

Olá, turma! 👋 Professor [Seu Nome/Prof. Shopify] aqui, e sejam muito bem-vindos à Aula 77 do nosso curso “Loja Shopify do Zero ao Avançado”!

Chegamos a um ponto fascinante e extremamente poderoso da nossa jornada. Até agora, exploramos muitas formas de personalizar e estender o Shopify, desde temas Liquid até a criação de aplicativos personalizados que interagem com a API. Mas e se eu disser que existe uma nova fronteira para levar a lógica de negócios da sua loja a um nível que antes era quase impossível para desenvolvedores de apps e lojas personalizadas?

Preparem-se, porque nesta aula vamos mergulhar de cabeça no universo das Shopify Functions e da extensibilidade avançada. Isso é o futuro do desenvolvimento no Shopify, e dominá-las colocará vocês à frente! 🚀

Aula 77 – Loja Shopify do Zero ao Avançado: Shopify Functions e extensibilidade avançada

📚 O que você vai aprender nesta aula

Ao final desta aula, você será capaz de:

  • Compreender o que são Shopify Functions e por que elas são uma peça fundamental na extensibilidade moderna do Shopify.
  • Distinguir Shopify Functions de soluções legadas como o Script Editor.
  • Entender a arquitetura por trás das Functions (WebAssembly e Function API).
  • Identificar os principais tipos de Shopify Functions e seus casos de uso.
  • Configurar um ambiente de desenvolvimento local para Shopify Functions usando o Shopify CLI.
  • Criar e implantar sua primeira Shopify Function usando Rust (ou outra linguagem compilada para Wasm).
  • Integrar Shopify Functions com o fluxo de checkout e carrinho.
  • Aplicar boas práticas no desenvolvimento de Functions.

🔗 Conectando com aulas anteriores

Nas aulas anteriores, exploramos a fundo a customização de temas com Liquid, criamos snippets e seções personalizadas para dar vida ao frontend da nossa loja. Também nos aprofundamos na criação de aplicativos personalizados (Custom Apps), aprendendo a interagir com a Admin API para gerenciar dados, e até mesmo a criar interfaces de usuário no painel administrativo do Shopify. Lembram-se de como usamos o Shopify CLI para iniciar projetos de apps e gerenciar ambientes? Essa ferramenta será nossa grande aliada novamente hoje! 🛠️

Mencionamos repetidamente que o checkout do Shopify é uma área altamente restrita por motivos de segurança e performance. Isso significava que, para lógica complexa de frete, pagamentos ou validações de carrinho que não podiam ser feitas com Liquid ou apps externos via webhooks/APIs, precisávamos recorrer a soluções mais limitadas ou até mesmo a plataformas de checkout de terceiros.

Em aulas anteriores, talvez tenhamos até discutido o Script Editor (Editor de Scripts), uma ferramenta mais antiga que permitia alguma lógica customizada no checkout. Bem, as Shopify Functions são a evolução (e substituição) dessa ferramenta, oferecendo muito mais poder, flexibilidade e performance. Elas representam a forma moderna e oficial de estender o coração da lógica de negócios do Shopify, permitindo que a gente influencie o comportamento do carrinho e do checkout de maneiras antes impossíveis sem sair da plataforma. Preparem-se para abrir a “caixa preta” do checkout de uma forma totalmente nova! 🤯

📖 Conteúdo Principal

O que são Shopify Functions?

Shopify Functions são uma nova e poderosa forma de estender a lógica de negócios central do Shopify. Elas permitem que você adicione lógica personalizada que é executada dentro do ambiente do Shopify, afetando diretamente como o carrinho, checkout, pagamentos e fretes funcionam. Pense nelas como pequenos programas otimizados que o Shopify executa em momentos chave do ciclo de compra.

Por que Shopify Functions? A Revolução da Extensibilidade 🚀

1. Substituição do Script Editor (Legacy): A principal motivação foi substituir o Script Editor, que era limitado em funcionalidades, performance e flexibilidade. O Script Editor usava uma linguagem Ruby (com uma DSL proprietária) e tinha um modelo de execução menos eficiente. As Functions são o futuro, e o Script Editor será desativado em breve para novas lojas.

2. Performance e Confiabilidade: As Functions são construídas com WebAssembly (Wasm), uma tecnologia que permite código de alta performance, executado de forma rápida e segura. Isso significa que sua lógica personalizada não vai atrasar o checkout, uma preocupação crítica para qualquer loja virtual.

3. Flexibilidade e Poder: Você pode escrever Functions em linguagens como Rust (a linguagem primária suportada pela Shopify, mas outras linguagens que compilam para Wasm podem ser usadas), o que oferece um poder de processamento e lógica muito maior do que as soluções anteriores.

4. Integração Nativa: Elas são executadas dentro da plataforma Shopify, o que significa que se integram perfeitamente com o ecossistema, o painel administrativo e as APIs.

5. Extensão do Core: Permitem estender pontos críticos do Shopify que antes eram “caixa-preta”, como a validação do carrinho, a personalização de métodos de pagamento e frete, e até o roteamento de pedidos.

A Arquitetura por Trás: WebAssembly (Wasm) e Function API

As Shopify Functions são executadas como módulos WebAssembly (Wasm). Mas o que é Wasm?

WebAssembly (Wasm): É um formato de instrução binária de baixo nível, projetado para ser um alvo de compilação de linguagens de programação de alto nível como C/C++, Rust, Go, entre outras. Ele permite a execução de código quase nativo em navegadores web e em ambientes de servidor* (como o Shopify), com segurança, portabilidade e alta performance. Em outras palavras, ele permite que você escreva lógica complexa em linguagens poderosas e a execute muito rapidamente, sem overhead.

  • Function API: Cada tipo de Function possui uma API específica (input/output) que define como ela se comunica com o Shopify. Por exemplo, uma Cart Transform Function receberá o estado atual do carrinho como input e retornará um conjunto de alterações ou transformações a serem aplicadas.
Tipos de Shopify Functions e Casos de Uso 🧩

A Shopify continua expandindo os “tipos” de Functions disponíveis. Os mais comuns e poderosos incluem:

1. Cart & Checkout Validation Functions:

  • Casos de Uso: Validar o conteúdo do carrinho (ex: mínimo de itens, máximo de itens, combinações proibidas), impedir que um cliente finalize a compra se certas condições não forem atendidas (ex: CPF/CNPJ inválido, itens fora do estoque, promoção não aplicada corretamente).

Exemplo: Se o cliente tem um produto “X” no carrinho, ele deve* ter um produto “Y” também. Caso contrário, impeça o checkout.

Cart Transform Functions: Um subtipo específico que permite modificar o carrinho (adicionar itens, aplicar descontos, remover itens) antes* da finalização.

  • Exemplo: Adicionar um brinde grátis automaticamente se o carrinho atingir um valor mínimo.

2. Payment Customization Functions:

  • Casos de Uso: Ocultar, reordenar ou renomear opções de pagamento disponíveis para o cliente com base no conteúdo do carrinho, no valor do pedido, no cliente ou no endereço de entrega.
  • Exemplo: Desabilitar “Boleto Bancário” se o valor do pedido for inferior a R$50,00 ou se o cliente for internacional.

3. Shipping Customization Functions:

  • Casos de Uso: Ocultar, reordenar ou renomear opções de frete disponíveis com base no conteúdo do carrinho, no cliente, no endereço de entrega ou no valor total do pedido.
  • Exemplo: Oferecer “Frete Expresso Grátis” apenas para clientes VIP ou para pedidos acima de R$300,00 que contenham produtos da coleção “Premium”.

4. Order Routing Functions (Menos comum para custom dev, mais para apps):

  • Casos de Uso: Definir regras complexas para rotear pedidos para diferentes locais de atendimento (fulfillment locations) com base em SKUs, inventário, localização do cliente, etc.
O Workflow de Desenvolvimento com Shopify CLI 👩‍💻

O desenvolvimento de Functions é integrado ao Shopify CLI, a mesma ferramenta que usamos para apps e temas.

1. Criação: Use shopify app generate function para criar a estrutura inicial da sua Function.

2. Linguagem: O Shopify CLI gerará um projeto Rust (o mais comum), mas você pode integrar outras linguagens que compilam para Wasm.

3. Desenvolvimento: Escreva sua lógica em Rust (ou outra linguagem), implementando a interface da Function API.

4. Testes: Teste sua Function localmente com inputs mockados.

5. Deploy: Faça o deploy da sua Function para o Shopify usando o CLI. Isso gera um .wasm que é enviado para os servidores da Shopify.

6. Ativação/Configuração: Uma vez implantada, a Function aparece no Admin da Shopify (geralmente em “Configurações” > “Apps e canais de vendas” ou em configurações de checkout/frete/pagamento) onde você pode ativá-la e, se aplicável, configurar seus parâmetros (via UI extensions).

💻 Exemplos Práticos

Vamos criar uma Cart Transform Function que adiciona um brinde gratuito ao carrinho se o valor total exceder R$200,00.

Pré-requisitos:

  • Shopify CLI instalado e atualizado (versão 3.x).
  • Rustup (gerenciador de ferramentas Rust) instalado. Isso é crucial para compilar o código Rust para Wasm. Siga as instruções em rustup.rs.
  • Um Partner Account e uma Development Store conectada ao seu CLI (já fizemos isso em aulas de Apps).

Passo 1: Criar um novo projeto de App com uma Function

As Functions são criadas dentro do contexto de um aplicativo (app) Shopify. Pode ser um app privado (custom app) ou um app público.

1. Abra seu terminal e navegue até a pasta onde você guarda seus projetos.

2. Crie um novo app, que incluirá nossa Function:

bash

shopify app generate

  • Nome do App: minha-loja-funcoes-app (ou o nome que preferir)
  • Tipo de App: Custom app (se for para uma única loja)
  • Funcionalidades a incluir: Marque Function
  • Tipo de Function: Cart and checkout (Vamos escolher essa para o Cart Transform)
  • Subtipo da Function: Cart transform
  • Linguagem da Function: Rust

O Shopify CLI vai criar uma nova pasta (minha-loja-funcoes-app) e dentro dela, uma subpasta para a Function (functions/cart-transform-brinde).

Imagine uma screenshot do terminal com os prompts e suas respostas, e o output de sucesso da criação do projeto.

3. Entre na pasta do seu novo app:

bash

cd minha-loja-funcoes-app

Passo 2: Entender a estrutura do projeto da Function

Abra o projeto no seu editor de código (VS Code é recomendado).

Dentro de minha-loja-funcoes-app/functions/cart-transform-brinde/:

  • src/main.rs: É onde a lógica Rust da sua Function reside.
  • Cargo.toml: O arquivo de manifesto do Rust, similar ao package.json do Node.js ou composer.json do PHP. Ele define as dependências e metadados do projeto Rust.
  • shopify.function.extension.toml: Este arquivo é específico da Shopify e define as propriedades da sua Function, como seu tipo (cart_transform) e o ponto de entrada.

Conteúdo de shopify.function.extension.toml:

toml

name = "cart-transform-brinde"

type = "cart_transform" # Define o tipo da sua Function

api_version = "2024-04" # Versão da API da Shopify que a Function usa

[build]

command = "cargo wasi build --release" # Comando para construir o Wasm

path = "target/wasm32-wasi/release/cart_transform_brinde.wasm" # Caminho do arquivo Wasm gerado

[ui.paths]

create = "/apps/minha-loja-funcoes-app/cart-transform-brinde/new" # Caminhos para UI de configuração no Admin

details = "/apps/minha-loja-funcoes-app/cart-transform-brinde/{functionId}"

Passo 3: Implementar a lógica da Function em src/main.rs

Vamos modificar src/main.rs para adicionar um brinde. Para simplificar, vamos adicionar um produto com um variant ID específico. Você precisará de um variant ID de um produto existente em sua loja de desenvolvimento. Crie um produto simples, como “Brinde Grátis”, e anote seu ID de variante.

rust

// src/main.rs

use shopify_function::prelude::*;

use shopify_function::result::Result;

use shopify_function::extension::r#type::cart_transform::{

output::{CartTransform, CartTransformOutput, CartTransformOperation},

input::{CartTransformInput, ProductVariant} // Importamos ProductVariant para pegar o ID

};

use serde::{Deserialize, Serialize};

// Definimos o ID do variante do nosso brinde.

// IMPORTANTE: Substitua 'SEU_VARIANT_ID_DO_BRINDE' pelo ID real de um produto de brinde na sua loja de desenvolvimento.

const GIFT_VARIANT_ID: &str = "SEU_VARIANT_ID_DO_BRINDE"; // Ex: "40578854006847"

#[shopify_function]

fn function(input: CartTransformInput) -> Result {

// Verificamos se o valor total do carrinho (sem frete) é maior que R$200

// A API da Function nos dá o subtotal do carrinho.

let cart_subtotal_amount: f64 = input.cart.lines.iter().map(|line| {

line.price.amount.parse::().unwrap_or_default() * line.quantity as f64

}).sum();

// Debugging (você pode ver isso no log do CLI quando rodar localmente)

eprintln!("Subtotal do carrinho: {:?}", cart_subtotal_amount);

let mut transformations: Vec = Vec::new();

if cart_subtotal_amount >= 200.0 {

// Verificamos se o brinde já está no carrinho para evitar duplicidade

let gift_already_in_cart = input.cart.lines.iter().any(|line| {

line.merchandise.as_ref().map_or(false, |m| {

if let ProductVariant::ProductVariant { id, .. } = m {

id.contains(GIFT_VARIANT_ID)

} else {

false

}

})

});

if !gift_already_in_cart {

// Adiciona o brinde ao carrinho

eprintln!("Adicionando brinde ao carrinho!");

transformations.push(CartTransformOperation::Add {

quantity: 1,

merchandise_id: GIFT_VARIANT_ID.to_string(), // Usamos o ID do variante do brinde

// Podemos adicionar atributos personalizados aqui se necessário

attributes: vec![],

});

}

} else {

// Se o valor do carrinho cair abaixo de R$200 e o brinde estiver lá, removemos.

// Isso garante que o brinde só apareça se as condições forem atendidas.

if let Some(gift_line_id) = input.cart.lines.iter().find_map(|line| {

if line.merchandise.as_ref().map_or(false, |m| {

if let ProductVariant::ProductVariant { id, .. } = m {

id.contains(GIFT_VARIANT_ID)

} else {

false

}

}) {

Some(line.id.to_string()) // Retorna o ID da linha do brinde

} else {

None

}

}) {

eprintln!("Removendo brinde do carrinho!");

transformations.push(CartTransformOperation::Remove {

cart_line_id: gift_line_id,

});

}

}

Ok(CartTransformOutput {

transformations: transformations,

// Outras opções de saída podem ser adicionadas aqui

})

}

// O código abaixo é apenas para fins de teste local e não afeta a lógica da Function em produção.

// Ele permite que você simule a entrada da Function usando um arquivo JSON.

// #[cfg(test)]

// mod tests {

// use super::*;

// use serde_json;

// #[test]

// fn test_function_add_gift() {

// // Um exemplo de input JSON para um carrinho que atende à condição

// let input_json = r#"{

// "cart": {

// "lines": [

// {

// "id": "gid://shopify/CartLine/1",

// "merchandise": {

// "__typename": "ProductVariant",

// "id": "gid://shopify/ProductVariant/OUTRO_PRODUTO_ID",

// "product": {

// "id": "gid://shopify/Product/OUTRO_PRODUTO_PRODUTO_ID"

// },

// "title": "Produto Caro",

// "sku": null

// },

// "quantity": 1,

// "price": { "amount": "250.00", "currencyCode": "BRL" }

// }

// ]

// }

// }"#;

// let input: CartTransformInput = serde_json::from_str(input_json).unwrap();

// let output = function(input).unwrap();

// assert_eq!(output.transformations.len(), 1);

// // Verifique se a transformação é para adicionar o brinde

// if let CartTransformOperation::Add { merchandise_id, .. } = &output.transformations[0] {

// assert!(merchandise_id.contains(GIFT_VARIANT_ID));

// } else {

// panic!("Esperava uma operação de adição");

// }

// }

// #[test]

// fn test_function_no_gift() {

// // Um exemplo de input JSON para um carrinho que não atende à condição

// let input_json = r#"{

// "cart": {

// "lines": [

// {

// "id": "gid://shopify/CartLine/2",

// "merchandise": {

// "__typename": "ProductVariant",

// "id": "gid://shopify/ProductVariant/PRODUTO_BARATO_ID",

// "product": {

// "id": "gid://shopify/Product/PRODUTO_BARATO_PRODUTO_ID"

// },

// "title": "Produto Barato",

// "sku": null

// },

// "quantity": 1,

// "price": { "amount": "150.00", "currencyCode": "BRL" }

// }

// ]

// }

// }"#;

// let input: CartTransformInput = serde_json::from_str(input_json).unwrap();

// let output = function(input).unwrap();

// assert_eq!(output.transformations.len(), 0); // Não deve adicionar nada

// }

// }

Dica importante: O eprintln! é uma ótima forma de “debugar” sua Function, pois ele imprime mensagens no console quando você a executa localmente.

Passo 4: Testar a Function Localmente

Antes de implantar, podemos testar nossa Function com dados simulados.

1. No diretório raiz do seu app (minha-loja-funcoes-app), execute:

bash

shopify app dev

Isso vai compilar sua Function e disponibilizar um link para o preview da loja.

Imagine uma screenshot do terminal com o output de shopify app dev e o link para a loja de desenvolvimento.

2. A Shopify CLI também fornecerá um link para o Admin para configurar as extensões. Vá até lá para ativar sua Function. No Admin da loja de desenvolvimento, vá em Configurações > Apps e canais de vendas > Minha Loja Funções App > Extensões. Você deve ver sua “Cart Transform Brinde” lá.

Imagine uma screenshot do Admin da Shopify mostrando a lista de extensões do app e a Function “Cart Transform Brinde” listada.

3. No mesmo local, clique na Function para ativá-la. Para o Cart Transform, geralmente não há uma UI de configuração complexa via Admin (a lógica está no código), apenas uma chave liga/desliga.

4. Agora, vá para o frontend da sua loja de desenvolvimento (o link que o shopify app dev forneceu).

  • Teste 1: Adicione produtos que totalizem menos de R$200. O brinde não deve aparecer no carrinho.
  • Teste 2: Adicione produtos que totalizem R$200 ou mais. O brinde (com o variant ID que você especificou) deve aparecer automaticamente no carrinho!
  • Teste 3: Se você tinha o brinde e removeu produtos, veja se ele desaparece automaticamente.

Passo 5: Implantar (Deploy) a Function

Quando estiver satisfeito com o comportamento local, é hora de implantar sua Function.

1. Certifique-se de que o Shopify CLI está logado na sua Partner Account:

bash

shopify login --store SEU_DOMINIO_DA_LOJA_DEV.myshopify.com

(Substitua pelo domínio da sua loja de desenvolvimento, ex: minha-loja-aula-77.myshopify.com)

2. No diretório raiz do seu app (minha-loja-funcoes-app), faça o deploy:

bash

shopify app deploy

O CLI fará o build do seu código Rust para Wasm, fará o upload para o Shopify e criará uma nova versão da sua Function.

Imagine uma screenshot do terminal com o output do shopify app deploy mostrando o sucesso do upload.

3. Após o deploy, a Function estará disponível no Admin da loja para ser ativada ou reconfigurada, se necessário. Se você já a ativou durante o teste local, ela continuará ativa com a nova versão.

Dicas de Boas Práticas e Otimização ✨

  • Validação de Input: Sempre valide os dados de entrada da sua Function. Embora o Shopify forneça dados estruturados, um tratamento robusto de None ou null é essencial em Rust.
  • Performance: Mantenha sua lógica o mais eficiente possível. As Functions são executadas em cada interação crítica do cliente (adicionar ao carrinho, avançar no checkout), então qualquer atraso pode impactar a experiência do usuário. Evite loops desnecessários ou operações complexas.
  • Modularidade: Para lógicas mais complexas, organize seu código Rust em módulos (mod.rs).
  • Testes: Escreva testes unitários para sua lógica Rust. Isso garante que a Function se comporte como esperado em diferentes cenários.
  • Versionamento: O Shopify CLI gerencia o versionamento das suas Functions como parte do app. Use commits significativos para registrar suas alterações.
  • Mensagens de Erro Claras: Se sua Function precisar retornar um erro (ex: validação de checkout falhou), certifique-se de que a mensagem seja útil para o cliente final.

🎯 Exercícios e Desafios

1. Checkout Validation Function: Crie uma nova Function do tipo Checkout Validation dentro do seu app. Essa Function deve impedir o checkout se o cliente tentar comprar mais de 5 unidades de um produto específico (escolha um produto da sua loja). Retorne uma mensagem de erro clara.

  • Dica: Você precisará criar um novo shopify app generate function e escolher o tipo Checkout Validation. A lógica será similar, mas a saída será um Result que pode conter errors.

2. Payment Customization: Crie uma Function que oculte a opção de pagamento “Cartão de Crédito” se o valor total do carrinho for inferior a R$10,00.

  • Dica: O tipo de Function será Payment Customization. Você receberá as opções de pagamento disponíveis e deverá retornar quais delas devem ser ocultadas, renomeadas ou reordenadas.

3. Refatoração do Brinde: Modifique a Cart Transform Function de brinde para que o GIFT_VARIANT_ID não seja um const fixo no código, mas sim configurável via metafields ou via uma UI Extension no Admin do Shopify (abordaremos UI Extensions em maior detalhe em aulas futuras, mas você pode pesquisar sobre app_config ou settings para functions).

  • Dica: Isso é mais avançado. Para esta aula, um simples const é aceitável, mas para o desafio, comece a pensar em como externalizar configurações.

📝 Resumo da Aula

Nesta aula crucial, desvendamos o poder das Shopify Functions! Aprendemos que elas são a nova geração de extensibilidade do Shopify, substituindo o Script Editor e permitindo lógica de negócios customizada, de alta performance e segura, diretamente no coração do checkout e do carrinho.

Compreendemos sua arquitetura baseada em WebAssembly (Wasm) e a API específica para cada tipo de Function. Exploramos os principais tipos como Cart Transform, Checkout Validation, Payment Customization e Shipping Customization, com exemplos práticos de seus usos.

Através de um exemplo detalhado, configuramos um ambiente de desenvolvimento, criamos uma Cart Transform Function em Rust para adicionar um brinde automático, testamos localmente com o shopify app dev e, finalmente, implantamos nossa solução com shopify app deploy.

As Shopify Functions abrem um leque gigantesco de possibilidades para criar experiências de compra verdadeiramente personalizadas e complexas, sem comprometer a segurança ou a performance do Shopify. Vocês acabaram de dar um passo gigantesco em direção à maestria em desenvolvimento Shopify! 🌟

🚀 Preparação para próxima aula

Ufa! Que aula intensa e cheia de novidades! As Shopify Functions são poderosas por si só, mas sua capacidade de serem configuradas e gerenciadas de forma amigável no Admin do Shopify é complementada por outra ferramenta essencial: as UI Extensions.

Na próxima aula, vamos mergulhar no mundo das Shopify UI Extensions, focando em como podemos criar interfaces de usuário personalizadas no Admin da Shopify (para configurar nossas Functions, por exemplo) e, mais importante, como podemos customizar a interface do próprio checkout. Pense em adicionar campos personalizados, banners ou até mesmo novas etapas visuais ao checkout! Veremos como as UI Extensions e as Functions se complementam para oferecer uma experiência de checkout totalmente única e sob medida.

Preparem-se para um controle ainda maior sobre a experiência do usuário! Até lá! 👋

📚 Recursos Adicionais

Continuem praticando e explorando! A comunidade Shopify está sempre crescendo, e o conhecimento de Shopify Functions é um diferencial enorme no mercado! 🌐

🚀 Pronto para a próxima aula?

Continue sua jornada Shopify!

Ver todas as aulas