@dscodotco/theme-cli
Version:
A CLI tool for developing Shopify themes
100 lines (88 loc) • 3.04 kB
text/typescript
import { createLogger } from "../logger.js";
import { ShopifyCredentials, ThemeManager } from "./theme-manager.js";
import Shopify from "shopify-api-node";
import fetch from "node-fetch";
import path from "path";
import fs from "fs";
import got from "got";
import crypto from "crypto";
const logger = createLogger("shopify-renderer");
export interface RendererOptions {
credentials: ShopifyCredentials;
themeId: number;
shopify: Shopify;
}
/**
* A service for rendering Shopify Liquid templates
* using Shopify's own rendering engine via the Admin API
*/
export class ShopifyRenderer {
private credentials: ShopifyCredentials;
private themeId: number;
private shopify: Shopify;
private baseUrl: string;
/**
* Creates a new ShopifyRenderer instance
* @param options Renderer configuration options
*/
constructor(options: RendererOptions) {
this.credentials = options.credentials;
this.themeId = options.themeId;
this.shopify = options.shopify;
this.baseUrl = `https://${options.credentials.storeName}.myshopify.com`;
}
/**
* Renders a template by uploading it to Shopify and fetching the rendered content
*/
async renderTemplate(content: string): Promise<string> {
// Generate a unique key for this template
const key = `templates/${crypto.randomBytes(6).toString("hex")}.liquid`;
// Log debug info
logger.info("=== Debug Info ===");
logger.info(`Template Key: ${key}`);
logger.info(`Template Content: ${content}`);
logger.info(`Theme ID: ${this.themeId}`);
logger.info(`Store URL: ${this.baseUrl}`);
try {
// Step 1: Create a temporary asset with our template
logger.info("Step 1: Creating temporary asset");
await this.shopify.asset.create(this.themeId, {
key,
value: content,
});
logger.info("✓ Asset created successfully");
// Step 2: Fetch the rendered content
logger.info(
`Step 2: Fetching from URL: ${this.baseUrl}/?view=${key.split(".")[1]}`
);
const response = await got(`${this.baseUrl}/?view=${key.split(".")[1]}`, {
headers: {
"X-Shopify-Access-Token": this.credentials.password,
},
});
logger.info("✓ Content fetched successfully");
logger.info(`Response length: ${response.body.length} characters`);
// Step 3: Clean up the temporary asset
logger.info("Step 3: Cleaning up temporary asset");
try {
await this.shopify.asset.delete(this.themeId, key);
logger.info("✓ Asset deleted successfully");
} catch (error) {
logger.error("✗ Asset deletion failed:");
logger.error(error);
}
return response.body;
} catch (error) {
logger.error("✗ Template rendering failed:");
logger.error(error);
throw error;
}
}
/**
* Gets the URL for previewing the current template
* @returns The preview URL
*/
getPreviewUrl(): string {
return `${this.baseUrl}?preview_theme_id=${this.themeId}`;
}
}