UNPKG

@dscodotco/theme-cli

Version:

A CLI tool for developing Shopify themes

128 lines (126 loc) 4.87 kB
/** * @module commands/shopify/theme/init * @description Commands for initializing Shopify themes */ import path from "path"; import fs from "fs"; import ora from "ora"; import { downloadFile } from "../../../utils/download.js"; import { extractZip } from "../../../utils/zip.js"; import { createLogger } from "../../../utils/logger.js"; const logger = createLogger("theme-init"); // Add debug mode flag let isDebugMode = false; /** * URL to the Dawn theme zip file on GitHub's main branch * @constant */ const DAWN_THEME_URL = "https://github.com/Shopify/dawn/archive/refs/heads/main.zip"; const ENV_EXAMPLE_CONTENT = `# Shopify store credentials SHOPIFY_STORE=your-store-name # e.g. your-store.myshopify.com SHOPIFY_API_KEY=your-api-key SHOPIFY_PASSWORD=your-admin-api-access-token # Development settings PORT=3000 # Optional, defaults to 3000 DEBUG=true # Optional, enables verbose logging`; /** * Creates necessary configuration files in the theme directory */ function createConfigFiles(themeDir) { // Create .env.example fs.writeFileSync(path.join(themeDir, ".env.example"), ENV_EXAMPLE_CONTENT); // Create .env if it doesn't exist const envPath = path.join(themeDir, ".env"); if (!fs.existsSync(envPath)) { fs.writeFileSync(envPath, ENV_EXAMPLE_CONTENT); } // Add .env to .gitignore if it exists const gitignorePath = path.join(themeDir, ".gitignore"); if (fs.existsSync(gitignorePath)) { const gitignoreContent = fs.readFileSync(gitignorePath, "utf-8"); if (!gitignoreContent.includes(".env")) { fs.appendFileSync(gitignorePath, "\n.env\n"); } } else { fs.writeFileSync(gitignorePath, ".env\n"); } } /** * Initializes a new Shopify theme by downloading and extracting the Dawn theme * * @param options - Configuration options for initializing the theme * @returns A promise that resolves when the theme is initialized * * @example * ```typescript * // Initialize a theme with default options * await initShopifyTheme(); * * // Initialize a theme with custom options * await initShopifyTheme({ * name: 'my-store-theme', * outputDir: './projects', * force: true * }); * ``` * * @throws Will throw an error if the theme initialization fails */ export async function initShopifyTheme(options) { isDebugMode = options.debug || false; if (isDebugMode) { logger.info("Debug mode enabled"); logger.info(`Initializing theme with options: ${JSON.stringify(options, null, 2)}`); } const themeDir = path.resolve(options.name || "."); if (isDebugMode) { logger.info(`Theme directory: ${themeDir}`); } // Check if directory exists and is not empty if (fs.existsSync(themeDir) && fs.readdirSync(themeDir).length > 0) { if (!options.force) { throw new Error(`Directory ${themeDir} already exists and is not empty. Use --force to overwrite.`); } if (isDebugMode) { logger.info("Force flag enabled, proceeding with existing directory"); } } const spinner = ora("Downloading Shopify Dawn theme...").start(); try { if (isDebugMode) { logger.info(`Downloading theme from: ${DAWN_THEME_URL}`); } // Download the theme const zipData = await downloadFile(DAWN_THEME_URL); spinner.text = "Extracting theme files..."; // Extract the theme (stripping the first directory which is 'dawn-main') if (isDebugMode) { logger.info(`Extracting theme to: ${themeDir}`); } extractZip(Buffer.from(zipData), themeDir, true); // Create configuration files if (isDebugMode) { logger.info("Creating configuration files..."); } createConfigFiles(themeDir); spinner.succeed(`Shopify theme initialized successfully in ${themeDir}`); // Show next steps logger.info("\nNext steps:"); logger.info(`1. cd ${options.name || "my-theme"}`); logger.info(`2. Configure your .env file with your Shopify credentials`); logger.info("3. Run 'npx @dscodotco/theme-cli shopify theme dev' to start the development server"); logger.info("\nFor more information, visit https://shopify.dev/themes"); // Show environment setup warning logger.warn("\nIMPORTANT: Before running the development server, you must configure your Shopify credentials in the .env file."); logger.info("We've created a .env file with example values. Please update it with your actual credentials."); } catch (error) { spinner.fail(`Failed to initialize theme: ${error.message}`); if (isDebugMode) { logger.error("Stack trace:"); logger.error(error.stack || "No stack trace available"); } throw error; } }