Skip to main content

@antinna/blogger-theme: Say Goodbye to Designing Single XML Files for Blogger

@antinna/blogger-theme: Say Goodbye to Designing Single XML Files for Blogger

Are you tired of designing one single, massive, and unmanageable XML file for your Google Blogger templates? Anyone who has ever tried to build a custom Blogger theme from scratch knows the absolute nightmare of editing thousands of lines of raw, inline styles, messy XML widget syntax, and archaic layouts in a single file. There is no code modularity, no component-based structure, and almost zero modern tooling support. Thankfully, the development experience has taken a massive leap forward. Introducing @antinna/blogger-theme—a revolutionary TypeScript and ESNext library designed to compile clean, modular TSX/JSX component structures into fully optimized, production-ready Blogger XML files automatically!

ℹ️ A Modern Approach to Legacy Blogging

Google's Blogger platform remains one of the most reliable and highly cost-effective engines for SEO and Google AdSense monetization due to its free hosting and zero operational maintenance. By compiling modern JSX components into the required Blogger XML format using @antinna/blogger-theme, you get the performance and developer experience of a modern static site generator (like Astro or React) combined with the robust, zero-cost scaling of Google's global server infrastructure!



Step 1 The Blogger Theme Pain Point: The Monolithic XML Nightmare

Standard modern web workflows are built on modularity. We write scoped CSS, independent HTML partials, and isolated TypeScript modules. Yet, when designing a template for Google Blogger, you are forced to throw these modern engineering practices out the window.

Blogger requires a single, monolithic .xml template file, which typically contains:

  • The entire master HTML backbone structure.
  • Messy inline CSS overrides wrapped inside critical <b:skin> or <b:template-skin> tags.
  • Outdated and verbose layout widget markup (such as <b:widget>, <b:section>, <b:if>, and <b:loop>).
  • Sparsely placed script files that block page rendering and slow down site load speeds.

Trying to collaborate in teams, use Git version control, or perform modular refactoring inside a 10,000-line XML monolith is practically impossible. It leads to silent parsing errors, broken templates, and immense developer fatigue.


Step 2 What is @antinna/blogger-theme?

The @antinna/blogger-theme package bridges this gap by acting as a modern compiler. Inspired by the Dart library blogger_theme, this library enables writing highly modular, extensible Blogger themes using TypeScript and TSX/JSX. You write clean, declarative component layout files, structured CSS classes, and modular client-side JavaScript. When compiled, the compiler processes your TSX trees, automatically resolves namespaces, wraps CSS inside appropriate skins, compiles client-side scripts via esbuild, and outputs a single, fully compliant Blogger XML file ready for upload.

✅ Major Benefits of Compiler-Driven Themes

By adopting @antinna/blogger-theme, you gain: full Git trackability of small modular files, high-speed automated asset compilation (including on-demand TypeScript/JavaScript bundling), XML-safe entity rendering, reusable partial widgets, and clean codebases that score perfect 100/100 marks on Google Lighthouse Core Web Vitals!


Step 3 Step-by-Step Guide: Quick Installation and Local Setup

To begin building structured Blogger themes, make sure you have Node.js installed locally. Initialize a brand-new project and install the compiler via NPM as a dependency. You will also want to install esbuild to take advantage of the client script bundling features:

$ npm init -y
$ npm install @antinna/blogger-theme esbuild

Next, construct a structured workspace to house your theme components. This keeps your development tree clean and organized:

📂 project-structure-preview
my-blogger-theme/
├── src/
│   ├── client/
│   │   └── analytics.ts         # Client-side dynamic interactive script
│   ├── components/
│   │   └── BlogLayout.tsx       # TSX modular layout structure
│   ├── types/
│   │   └── blogger-theme.d.ts   # Global JSX Type Declarations
│   └── main.tsx                 # Theme generation entrypoint
├── tsconfig.json                # TypeScript compiler config
└── package.json

Step 4 Step-by-Step Guide: Configuring tsconfig.json for TSX

To use TSX/JSX syntax in your project, configure your local tsconfig.json file. This instructs the TypeScript compiler to use the automatic JSX runtime provided by @antinna/blogger-theme, mapping JSX elements directly to the library's XML rendering engine:

📂 tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "jsx": "react-jsx",
    "jsxImportSource": "@antinna/blogger-theme",
    "strict": true
  }
}

Step 5 Step-by-Step Guide: Configuring Full JSX Global Typings (blogger-theme.d.ts)

To enable flawless TypeScript autocomplete and type safety for both standard HTML elements and specialized Blogger-native tags (like <b:section>, <b:widget>, <b:if>, etc.), configure a global typing definition file named src/types/blogger-theme.d.ts in your project. This maps the elements directly to the core Component class:

📂 src/types/blogger-theme.d.ts
import { Component } from '@antinna/blogger-theme';

declare global {
  namespace JSX {
    interface Element extends Component {}
    interface ElementClass extends Component {}

    interface HTMLAttributes {
      id?: string;
      class?: string;
      className?: string;
      style?: string;
      title?: string;
      name?: string;
      type?: string;
      value?: string | number;
      placeholder?: string;
      disabled?: boolean;
      href?: string;
      target?: string;
      src?: string;
      alt?: string;
      width?: string | number;
      height?: string | number;
      async?: boolean | string;
      defer?: boolean | string;
      rel?: string;
      media?: string;
      method?: string;
      action?: string;
      rows?: number;
      cols?: number;
      checked?: boolean;
      selected?: boolean;
      [attributeName: string]: any;
    }

    interface IntrinsicElements {
      // Standard HTML elements
      html: HTMLAttributes;
      head: HTMLAttributes;
      body: HTMLAttributes;
      title: HTMLAttributes;
      meta: HTMLAttributes;
      link: HTMLAttributes;
      base: HTMLAttributes;
      div: HTMLAttributes;
      span: HTMLAttributes;
      p: HTMLAttributes;
      h1: HTMLAttributes;
      h2: HTMLAttributes;
      h3: HTMLAttributes;
      h4: HTMLAttributes;
      h5: HTMLAttributes;
      h6: HTMLAttributes;
      ul: HTMLAttributes;
      li: HTMLAttributes;
      ol: HTMLAttributes;
      a: HTMLAttributes;
      img: HTMLAttributes;
      input: HTMLAttributes;
      button: HTMLAttributes;
      form: HTMLAttributes;
      label: HTMLAttributes;
      select: HTMLAttributes;
      option: HTMLAttributes;
      textarea: HTMLAttributes;
      script: HTMLAttributes & { src?: string; type?: string; async?: boolean | string; contentInCDATA?: boolean };
      style: HTMLAttributes;
      br: HTMLAttributes;
      hr: HTMLAttributes;
      header: HTMLAttributes;
      footer: HTMLAttributes;
      main: HTMLAttributes;
      nav: HTMLAttributes;
      section: HTMLAttributes;
      article: HTMLAttributes;
      aside: HTMLAttributes;
      details: HTMLAttributes;
      summary: HTMLAttributes;

      // Blogger native lowercase elements (for developers who prefer lowercase tag syntax)
      'b:section': HTMLAttributes & { id: string; class?: string; maxwidgets?: number | string; showaddelement?: boolean | string; growth?: string; preferred?: boolean | string };
      'b:widget': HTMLAttributes & { id: string; type: string; title?: string; locked?: boolean | string; pageType?: string; mobile?: string; version?: number | string; visible?: boolean | string };
      'b:widget-settings': HTMLAttributes;
      'b:widget-setting': HTMLAttributes & { name: string };
      'b:if': HTMLAttributes & { cond: string };
      'b:elseif': HTMLAttributes & { cond: string };
      'b:else': HTMLAttributes;
      'b:loop': HTMLAttributes & { values: string; var: string; index?: string };
      'b:include': HTMLAttributes & { name: string; data?: string; cond?: string };
      'b:includable': HTMLAttributes & { id: string; var?: string };
      'b:attr': HTMLAttributes & { name: string; value: string; 'expr:value'?: string; cond?: string };
      'b:class': HTMLAttributes & { name: string; cond: string };
      'b:tag': HTMLAttributes & { name?: string; cond?: string };
      'b:eval': HTMLAttributes & { expr: string };
      'b:with': HTMLAttributes & { var: string; value: string };
      'b:switch': HTMLAttributes & { var: string };
      'b:case': HTMLAttributes & { value: string };
      'b:default': HTMLAttributes;
      'b:message': HTMLAttributes & { name: string };
      'b:comment': HTMLAttributes;
      'b:template-skin': HTMLAttributes;
      'b:template-script': HTMLAttributes & { name: string; version: string; async?: boolean | string };
      'b:param': HTMLAttributes & { value?: string; 'expr:value'?: string };
      'b:defaultmarkup': HTMLAttributes & { type: string };
      'b:defaultmarkups': HTMLAttributes;

      // Dynamic tags fallback
      [elemName: string]: any;
    }
  }
}

Step 6 Step-by-Step Guide: Defining Layout Components in TSX

Now let's draft our modular layout component. Notice how we import components like BSection, BWidget, BIf, and BData directly from @antinna/blogger-theme. The global declarations we configured above guarantee full type safety during building!

📂 src/components/BlogLayout.tsx
import { BSection, BWidget, BIf, BData } from "@antinna/blogger-theme";

export const BlogLayout = () => (
  
{/* Master Header section wrapper */} {/* Conditionally render content only on single post pages */}

);

Step 7 Step-by-Step Guide: Generating the Blogger Theme XML (main.tsx)

In our main entrypoint file src/main.tsx, we initialize our theme utilizing the declarative TSX style. We import our layout, setup default layout versions, provide our skin CSS definitions, and invoke the generator to output the production template string:

📂 src/main.tsx
import { Component } from '@antinna/blogger-theme';
import {
  BloggerTheme,
  BSection,
  BWidget,
  BIf,
  BData,
  BSkin,
  Title,
  h,
  Fragment,
} from '@antinna/blogger-theme';

// 1. Define your layout component using TSX (Declarative JSX Style)
const BlogLayout = () => (
  
); // 2. Generate Blogger theme XML const theme = new BloggerTheme({ attributes: { 'b:responsive': 'true', 'b:defaultwidgetversion': '2', 'b:layoutsversion': '3', }, head: [ Generated Blogger Theme, , ], body: [], }); const xml = theme.generate(); console.log('--- GENERATED BLOGGER TEMPLATE XML ---'); console.log(xml); export default theme;

Step 8 Dual API Support: Builder Style vs JSX Compilation

One of the most impressive architectural aspects of @antinna/blogger-theme is its native Dual-API support. If you do not want to configure JSX or prefer a classic Object-Oriented Programming (OOP) syntax to dynamically construct elements matching the Dart structure, you can use built-in constructors directly!

Here is how the exact same layout structure is built using standard class-based builders instead of TSX:

📂 src/components/BuilderLayout.ts
import { BSection, BWidget, BIf, Div, BData, Article, H1 } from "@antinna/blogger-theme";

export const layout = new Div(
  { class: "wrapper-pane" },
  new BSection(
    {
      id: "header-area",
      className: "header-section",
      maxwidgets: 1,
      showaddelement: true,
    },
    new BWidget({
      id: "Header1",
      type: "Header",
      title: "Blog Header Title",
      locked: true,
    }),
  ),
  new BIf(
    { cond: "data:view.isPost" },
    new Div(
      { class: "post-item" },
      new Article(
        { class: "post-card" },
        new H1({}, new BData("data:blog.pageName")),
        new Div({ class: "post-body" }, new BData("post.body"))
      )
    ),
  ),
);

// Call direct render to get raw XML
const xml = layout.render();
Feature / Metric TSX/JSX Style Constructor / OOP Style
Readability Excellent; mirrors native HTML structure Moderate; nested constructors can feel nested
Setup Required Needs tsconfig.json configuration Zero config; runs anywhere in Node.js
IDE Support Type autocomplete with tags matching HTML/XML Excellent; parameter descriptions and type safety

Step 9 Advanced Feature: On-Demand Client Script Bundling with BClientScript

Normally, adding client-side script trackers, interactive analytics, or DOM manipulation libraries to Blogger involves uploading files elsewhere or manually pasting minified JavaScript code inside XML CDATA blocks. This completely breaks version control and maintainability.

With @antinna/blogger-theme, you can compile external TypeScript/JavaScript source files on-demand during the layout rendering stage! By using the <BClientScript /> component, the compiler invokes esbuild behind the scenes to bundle, minify, and wrap your file into a clean, self-invoking IIFE block instantly:

📂 src/client/analytics.ts
// Modular Client Script supporting TypeScript types
export const initAnalytics = (trackingId: string): void => {
  console.log(`[Antinna Analytics] Initializing track ID: ${trackingId}`);
  window.addEventListener("DOMContentLoaded", () => {
    const pageViewData = {
      href: window.location.href,
      referrer: document.referrer,
      time: new Date().toISOString()
    };
    // Send telemetry data
    navigator.sendBeacon("/api/log", JSON.stringify(pageViewData));
  });
};

initAnalytics("UA-99887766-1");

To bundle this script directly inside your master layout, include the component in your layout or head. During theme compilation, it renders an optimized <script> element with full minification and CDATA escaping automatically:

📂 Embedding BClientScript
import { BClientScript } from "@antinna/blogger-theme";

// Inside your TSX header head array or layout body:

Step 10 Step-by-Step Guide: Compiling Your Theme via CLI

To compile your theme entry file easily, configure short package scripts that automatically ensure target distribution folders exist before running the compiler. This prevents directory-not-found errors during compilation:

📂 package.json
{
  "scripts": {
    "build": "node -e \"require('fs').mkdirSync('dist', { recursive: true })\" && npx @antinna/blogger-theme ./src/main.tsx --out ./dist/theme.xml",
    "watch": "node -e \"require('fs').mkdirSync('dist', { recursive: true })\" && npx @antinna/blogger-theme ./src/main.tsx --out ./dist/theme.xml --watch"
  }
}

Execute the automated build command. The compiler will aggregate and process your layout tree, compile your assets, and output the target theme.xml file in less than 50 milliseconds:

$ npm run build

Voila! Open your dist/theme.xml file, copy its compiled text, and paste it directly into the HTML editor of your Blogger dashboard. You now have an advanced, robust, and lightning-fast theme built with modern, structured TypeScript coding practices!


Step 11 Best Practices for Developing High-Performance Blogger Themes

To maximize your site speed, maintain clean structures, and ensure proper schema validation, keep these key best practices in mind:

  1. Leverage BClientScript: Avoid inline scripts inside layouts. Keeping JS in separate TypeScript files ensures full syntax checks, type safety, and automatic render-time bundling.
  2. Use Scoped CSS: Since XML files can grow large, write scoped CSS classes inside specific component functions or use utility frameworks to prevent styles from leaking.
  3. Keep Elements Nested Correctly: Ensure that interactive Blogger tags (like BData, BIf, and nested BWidget elements) are nested inside parent BSection wrappers to satisfy standard Blogger platform rules.
  4. Enable Strict Types: Do not bypass TypeScript compiler alerts. Correct type checks prevent layout variables from rendering empty tags.

Step 12 Summary and Next Steps

Designing modern, responsive themes for Google's Blogger platform no longer requires struggling with messy monolithic XML files. By utilizing the declarative compiler power of @antinna/blogger-theme, you can build modular, type-safe templates with React-like TSX layouts, automated CDATA client-script bundling, and full esbuild integration.

Take control of your template directories today by checking out the official package on npm:

$ npm view @antinna/blogger-theme

📄 Contributions & Licensing

The @antinna/blogger-theme package is published under the permissive MIT License. Have questions about setting up modular build systems? Join the discussion or leave a comment below!

Comments

Contact:

Popular posts from this blog

Flutter™ Installation Without Android Studio™

When developing with Flutter™, you typically install Android Studio™ as part of the setup process. However, if you want a lightweight alternative, you can install Flutter™ with only the Android command-line tools. This guide walks you through the steps to set up a performant, studio-free development environment on Windows. Table of Contents 1. Install Command-Line Tools 2. Install SDK Components 3. Set Environment Variables 4. Configure Flutter™ 1. Install Command-Line Tools First, download the Android SDK Command-Line Tools from the official Android Developer website . To ensure proper recognition by the Flutter SDK, extract the zip file following this directory structure: 📂 Path Structure Copy C:\Users\ \AppData\Local\Android\Sdk\cmdline-tools\latest\bin 2. Install SDK C...

Android CLI: Beyond the IDE

Agent-First Workflows Android CLI Command Reference The Android CLI is a unified developer interface architected to standardize environment control, workspace orchestration, and execution capabilities for standalone developer loops and automated AI agents. It serves as an optimized runtime engine connecting local projects directly to official tools, execution layers, and the centralized Android Knowledge Base . Quick Navigation Index Setup & Init Telemetry Scopes Global Option Flags Workspace Scaffolding Agent Systems Device & Vision Layers Toolchain & SDK IDE Deep Integration Installation & Global Setup Follow these structural phases to establish the system binary paths and expose core system hooks to target development execution layers. Phase 1 Bina...

Building a Modular Project with a Monorepo Using Pub Workspaces Feature

Flutter™  projects often start small, but as they scale, managing multiple packages becomes challenging. If you find yourself working with several modules or features in one project, organizing them efficiently is crucial. Enter Monorepos with Pub Workspaces – an excellent solution for managing a Flutter project with multiple packages in a modular way. In this post, we’ll explore how to structure a Flutter project in a modular way using a monorepo , and how to manage dependencies across various sub-projects without worrying about version conflicts. We’ll also look at how to configure Pub Workspaces to simplify dependency resolution and management. When working with Flutter™ and Dart™ , structuring a project in a modular way can improve scalability and maintainability. This is especially important when managing multiple packages in a single repository, also known as a monorepo . Pub Workspaces , introduced to simplify dependency management, provide a robust solution...