TurboDocx HTML to DOCX

repository·develop·Indexed 42 days ago

https://github.com/turbodocx/html-to-docx

A high-performance, pure JavaScript library for converting HTML to DOCX, Google Docs, and Word files. Version 1.21.0 supports both client-side generation (returning a Blob) and server-side generation in Node.js (returning a Buffer) without requiring external binaries like Puppeteer or LibreOffice. It features configurable page sizes, margins, and image processing, with native SVG embedding for browser environments and sharp-based rasterization for Node.js.

Tokens
7.1K
Snippets
24
Records
31
Agent score
53%

What's inside TurboDocx

  1. Configure SVG image support strategies

    develop

    The library supports two SVG handling strategies via the imageProcessing.svgHandling option. Choosing between them depends on your deployment constraints and target Word version compatibility.

    1. Convert to PNG (Maximum Compatibility)

    Converts SVGs to PNG format. This is the recommended approach for production applications that need to support all versions of Microsoft Word (including 2007+), Word Online, and Google Docs. Requirement: Requires sharp to be installed as a peer dependency.

    2. Native SVG (Modern Office Only)

    Embeds SVGs natively to preserve vector quality and reduce file size. Requirement: Only works with Microsoft Office 2019+, Microsoft 365, or Word for Mac 2019+. Warning: Older Word versions will display an "unreadable content" error if native SVGs are used.

    Automatic Fallback

    If sharp is not installed, the library will automatically fall back to native SVG embedding even if you have configured svgHandling: 'convert'.

    // Example: Explicitly setting SVG handling to 'convert' (requires sharp)
    const docx = await HTMLtoDOCX(htmlWithSVG, null, {
      imageProcessing: {
        svgHandling: 'convert'
      }
    });
    
    // Example: Explicitly setting SVG handling to 'native' (Office 2019+ only)
    const docx = await HTMLtoDOCX(htmlWithSVG, null, {
      imageProcessing: {
        svgHandling: 'native'
      }
    });
  2. Handling remote images in HTML

    develop

    When converting HTML to DOCX, remote images referenced by URL are fetched at generation time.

    Important considerations:

    • CORS: The image host must allow cross-origin requests if generating in the browser.
    • Workarounds: If CORS prevents browser-side fetching, you can pre-convert images to base64 data URLs or perform the generation on the server.
    • SVGs: In the browser, SVGs are embedded natively (supported by Word 2019+). Note that SVG-to-PNG rasterization via sharp is only available in Node.js environments.
  3. Note on Font Compatibility

    develop

    Font family styling may behave differently across various word processors:

    • Word Desktop: Works as intended.
    • LibreOffice: Ignores fontTable.xml and selects its own font.
    • Word Online: Ignores fontTable.xml and selects the closest match from its own font library.
  4. Understand browser environment limitations

    develop

    When using the library in a browser, be aware of the following constraints:

    • Sharp (SVG conversion): The sharp library is unavailable. SVG images will be embedded natively, which requires Office 2019 or newer to display correctly.
    • File System: The library cannot access the local file system directly. Documents must be handled as Blob or ArrayBuffer for downloading.
    • Image URLs: Remote images must have CORS enabled or be provided as base64 data URLs.
  5. Compatibility with Vite, webpack, SvelteKit, and Astro

    develop

    The @turbodocx/html-to-docx package includes a browser export condition in its exports map. This allows modern bundlers (Vite, webpack, Turbopack, etc.) to resolve to a self-contained ESM build that includes necessary Node polyfills.

    No manual aliasing or additional polyfill plugins (like vite-plugin-node-polyfills) are required for standard usage.

  6. Generate DOCX files on the server (Node.js)

    develop

    For server-side generation (e.g., in a Next.js Route Handler), the library returns a Buffer instead of a Blob.

    Benefits of server-side generation:

    • Smaller client-side JavaScript bundles.
    • Access to sharp for SVG-to-PNG rasterization (which is Node-only).
    • Better handling of remote images if CORS is an issue on the client.
    // app/api/docx/route.ts
    import HTMLtoDOCX from "@turbodocx/html-to-docx";
    
    export async function POST(req: Request) {
      const { html } = await req.json();
      // Returns a Buffer on the server
      const buffer = (await HTMLtoDOCX(html, undefined, {})) as Buffer;
      
      return new Response(new Uint8Array(buffer), {
        headers: {
          "Content-Type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
          "Content-Disposition": 'attachment; filename="document.docx"',
        },
      });
    }
  7. Test the browser build locally

    develop

    To verify your browser build is working correctly, you can run the included test server:

    1. Run npm run test:browser.
    2. Open http://localhost:8080/tests/test_browser.html in your browser.
    3. Use the test page to edit HTML and attempt to generate/download a DOCX file.
    npm run test:browser
  8. Generate DOCX files in the browser (Client-side)

    develop

    You can generate Word documents entirely in the browser without an API route. This is ideal for keeping the logic on the client and avoiding server round-trips.

    To optimize your bundle size, it is recommended to use a dynamic import() inside a user action (like a click handler). This ensures the library is code-split and only loaded when needed. The library returns a Blob when running in the browser.

    Key requirements for browser usage:

    • Use a Client Component ("use client" in Next.js).
    • The library's browser export condition handles Node polyfills automatically, so no special bundler configuration (like Buffer polyfills) is required.
    "use client";
    
    async function handleGenerate(html: string) {
      // Dynamic import for code-splitting
      const { default: HTMLtoDOCX } = await import("@turbodocx/html-to-docx");
    
      // Returns a Blob in the browser
      const blob = await HTMLtoDOCX(html, undefined, { title: "My Document" });
    
      const url = URL.createObjectURL(blob as Blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = "document.docx";
      a.click();
      setTimeout(() => URL.revokeObjectURL(url), 0);
    }
  9. Install @turbodocx/html-to-docx with SVG support

    develop

    Depending on your needs for package size and compatibility, choose one of the following installation methods:

    Lightweight Installation (No sharp)

    Best for size-constrained environments like AWS Lambda or Edge functions. Uses native SVG embedding (requires Office 2019+).

    • Package size: ~2.8MB
    • Command: npm install @turbodocx/html-to-docx

    Best for production applications requiring broad compatibility (works with Word 2007+). Converts SVGs to PNG.

    • Package size: ~2.8MB + ~34MB for platform-specific binaries
    • Command: npm install @turbodocx/html-to-docx sharp
    # Lightweight (Office 2019+ only)
    npm install @turbodocx/html-to-docx
    
    # Full (All Word versions - Recommended)
    npm install @turbodocx/html-to-docx sharp
  10. Use @turbodocx/html-to-docx in a browser environment

    develop

    The library provides a standalone browser build (html-to-docx.browser.js) that bundles all dependencies, allowing usage in HTML pages without build tools.

    Important: Runtime Polyfills Because some dependencies check for Node.js globals synchronously during initialization, you must set global, process, and Buffer polyfills in a <script> tag before loading the library.

    Usage Workflow

    1. Set up Node.js polyfills.
    2. Include the standalone browser build via <script>.
    3. Call HTMLToDOCX(htmlContent, options).
    4. Convert the result (Blob, ArrayBuffer, or Uint8Array) into a Blob to trigger a download.
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <title>HTML to DOCX Demo</title>
    </head>
    <body>
      <script>
        // Polyfills for Node.js globals (required before library loads)
        if (typeof global === 'undefined') window.global = window;
        if (typeof process === 'undefined') window.process = { env: {} };
        if (typeof Buffer === 'undefined') {
          window.Buffer = {
            from: function(data, encoding) {
              if (typeof data === 'string') {
                if (encoding === 'base64') {
                  var binary = atob(data);
                  var bytes = new Uint8Array(binary.length);
                  for (var i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
                  return bytes;
                }
                return new TextEncoder().encode(data);
              }
              return new Uint8Array(data);
            },
            isBuffer: function() { return false; }
          };
        }
      </script>
      
      <script src="path/to/html-to-docx.browser.js"></script>
      
      <script>
        async function generateDocument() {
          const htmlContent = `<h1>Hello World</h1><p>Generated in the browser.</p>`;
          try {
            const result = await HTMLToDOCX(htmlContent, null, { title: 'My Document' });
            
            // Convert result to Blob for download
            let blob;
            if (result instanceof Blob) {
              blob = result;
            } else if (result instanceof ArrayBuffer || result instanceof Uint8Array) {
              blob = new Blob([result], { 
                type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' 
              });
            }
            
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'document.docx';
            a.click();
            URL.revokeObjectURL(url);
          } catch (error) {
            console.error('Error:', error);
          }
        }
      </script>
      
      <button onclick="generateDocument()">Generate DOCX</button>
    </body>
    </html>