← back to Dw War Room

vite.config.ts

108 lines

import { defineConfig } from 'vite';
import { resolve } from 'path';
import https from 'https';

// Shopify GraphQL search proxy for Vite dev server
function shopifySearchPlugin() {
  const SHOPIFY_STORE = 'designer-laboratory-sandbox.myshopify.com';
  const SHOPIFY_TOKEN = (process.env.SHOPIFY_ADMIN_TOKEN || '');
  const API_VERSION = '2024-01';

  return {
    name: 'shopify-search-proxy',
    configureServer(server: any) {
      server.middlewares.use('/api/shopify/search', (req: any, res: any) => {
        const url = new URL(req.url || '/', `http://${req.headers.host}`);
        const query = url.searchParams.get('q') || '';
        const limit = Math.min(parseInt(url.searchParams.get('limit') || '10', 10), 20);

        if (query.length < 2) {
          res.writeHead(400, { 'Content-Type': 'application/json' });
          return res.end(JSON.stringify({ error: 'Query too short' }));
        }

        const gqlQuery = JSON.stringify({
          query: `{
            products(first: ${limit}, query: "${query.replace(/"/g, '\\"')}") {
              edges { node {
                id title vendor productType handle tags
                images(first: 1) { edges { node { url } } }
                variants(first: 1) { edges { node { price sku } } }
              }}
            }
          }`
        });

        const options = {
          hostname: SHOPIFY_STORE,
          path: `/admin/api/${API_VERSION}/graphql.json`,
          method: 'POST',
          headers: {
            'X-Shopify-Access-Token': SHOPIFY_TOKEN,
            'Content-Type': 'application/json',
            'Content-Length': Buffer.byteLength(gqlQuery),
          },
        };

        const proxyReq = https.request(options, (shopifyRes) => {
          let data = '';
          shopifyRes.on('data', (chunk: string) => { data += chunk; });
          shopifyRes.on('end', () => {
            try {
              const gql = JSON.parse(data);
              const edges = gql?.data?.products?.edges || [];
              const products = edges.map(({ node }: any) => ({
                id: parseInt(node.id.replace('gid://shopify/Product/', ''), 10),
                title: node.title,
                vendor: node.vendor,
                product_type: node.productType,
                handle: node.handle,
                tags: node.tags ? node.tags.join(', ') : '',
                images: node.images?.edges?.length
                  ? node.images.edges.map((e: any) => ({ src: e.node.url }))
                  : [],
                variants: node.variants?.edges?.length
                  ? node.variants.edges.map((e: any) => ({ price: e.node.price, sku: e.node.sku || '' }))
                  : [{ price: '0.00', sku: '' }],
              }));
              res.writeHead(200, { 'Content-Type': 'application/json' });
              res.end(JSON.stringify({ products }));
            } catch {
              res.writeHead(502, { 'Content-Type': 'application/json' });
              res.end(JSON.stringify({ error: 'Parse error', products: [] }));
            }
          });
        });

        proxyReq.on('error', () => {
          res.writeHead(502, { 'Content-Type': 'application/json' });
          res.end(JSON.stringify({ error: 'Proxy error', products: [] }));
        });

        proxyReq.write(gqlQuery);
        proxyReq.end();
      });
    },
  };
}

export default defineConfig({
  plugins: [shopifySearchPlugin()],
  server: {
    port: 4060,
    host: '0.0.0.0',
  },
  preview: {
    port: 4060,
    host: '0.0.0.0',
  },
  build: {
    rollupOptions: {
      input: {
        main: resolve(__dirname, 'index.html'),
        showroom: resolve(__dirname, 'showroom.html'),
      },
    },
  },
});