{"id":14982459,"url":"https://github.com/worlduniting/bookpub","last_synced_at":"2025-10-29T15:30:44.908Z","repository":{"id":142529191,"uuid":"612409630","full_name":"worlduniting/bookpub","owner":"worlduniting","description":"BookPub is an advanced book publishing framework for creating manuscripts in Markdown, HTML, CSS, Javascript, and publishing them into any format (PDF, ePub, MOBI, HTML, Print).","archived":false,"fork":false,"pushed_at":"2023-05-27T17:41:00.000Z","size":114710,"stargazers_count":10,"open_issues_count":4,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-02-08T02:06:16.281Z","etag":null,"topics":["css","ejs","ejs-partials","ejs-template-engine","epub","gfm","html","javascript","markdown","pdf","princexml","publishing","smartypants"],"latest_commit_sha":null,"homepage":"","language":"SCSS","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/worlduniting.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":"Code_Of_Conduct.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-03-10T22:13:14.000Z","updated_at":"2024-04-15T04:23:32.000Z","dependencies_parsed_at":"2023-06-28T15:01:14.491Z","dependency_job_id":null,"html_url":"https://github.com/worlduniting/bookpub","commit_stats":{"total_commits":37,"total_committers":2,"mean_commits":18.5,"dds":"0.027027027027026973","last_synced_commit":"0b1573bad100e3b7baf6f24bc2d166e2819701f5"},"previous_names":["worlduniting/bookshop"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/worlduniting%2Fbookpub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/worlduniting%2Fbookpub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/worlduniting%2Fbookpub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/worlduniting%2Fbookpub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/worlduniting","download_url":"https://codeload.github.com/worlduniting/bookpub/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238840721,"owners_count":19539602,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["css","ejs","ejs-partials","ejs-template-engine","epub","gfm","html","javascript","markdown","pdf","princexml","publishing","smartypants"],"created_at":"2024-09-24T14:05:27.131Z","updated_at":"2025-10-29T15:30:44.902Z","avatar_url":"https://github.com/worlduniting.png","language":"SCSS","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp\u003e\n  \u003cimg src=\"assets/logo-mid.svg\" align=\"right\"  hspace=\"60\" vspace=\"80\" width=\"30%\" height=\"30%\" alt=\"BookPub logo header\"/\u003e\n\u003c/p\u003e\n\n# bookpub\n\nA lightweight book publishing cli framework providing customizable pipelines with modular stages that can be stacked like legos to create any type/number of publishable assets you need---from only one manuscript source.\n\n\u003e Author's Note:\n\u003e\n\u003e My intent is to focus **bookpub** on orchestrating pipelines and stages in a standardized way so that users can easily add their own solutions (stages) for converting the manuscript.\n\u003e\n\u003eCurrently bookpub's pre-built stages utilize standard Web conventions for styling (HTML/CSS/JS).\n\n\n---\n\n## Table of Contents\n\n- [Features](#features)  \n- [Installation](#installation)  \n- [Quick Start](#quick-start)  \n- [Project Structure](#project-structure)  \n- [Using Pipelines or Stages](#using-pipelines-or-stages)  \n- [Working With Meta](#working-with-meta)  \n- [Overriding or Adding Stages](#overriding-or-adding-stages)  \n- [Build Outputs](#build-outputs)  \n- [Pandoc Markdown Tutorial](#pandoc-markdown-tutorial)  \n\n---\n\n## Features\n\n- **One Manuscript Source**\n  - The manuscript is written in industry-standard [Markdown](https://www.markdownguide.org/), wrapped in [EJS (Embedded JavaScript: a javascript based templating standard)](https://ejs.co/)  \n- **Stage-Based Pipelines**: Pipelines are composed of individual stages executed in sequence.\n  - Pre-Defined Build Pipelines:\n    - **HTML** - Creates an HTML build of your book.\n    - **PDF** - Creates a PDF build of your book.\n  - Pre-Built Stages:  \n    - **ejs** (EJS to Markdown)  \n    - **markdown** (Markdown to HTML using Pandoc)  \n    - **themes** (SCSS to CSS using SASS and coping assets)  \n    - **pdf** (html/css/js to PDF using PrinceXML)\n- **Extend or Override**:\n  - Drop in your own custom **stages**\n  - Define new build pipelines and their stages.\n  - Or Override built-in stages and/or pipelines.  \n- **Dev Mode**: View the final pipeline result in real time (via browser) as you edit the manuscript.  \n- **Project Settings (book.config.yml)**: Use [YAML](https://spacelift.io/blog/yaml) to define global, pipeline, or stage based settings\n  - **Meta** (e.g. title: My Title)\n  - **Config** (e.g. (for EJS... rmWhitespace: true))\n- **Scaffolding**: Spin up a new bookpub project with a single command that includes all the boilerplate.\n\n---\n\n## Pre-Requisites\n\n1. **Installing Pandoc**\n\n    bookpub uses pandoc in its built-in markdown stage\n    * (You can easily use something else by visiting the [Overriding or Adding Stages](#overriding-or-adding-stages) section)\n\n    Please visit the [Pandoc Installation Page](https://pandoc.org/installing.html) for directions on installing Pandoc on your operating system\n\n2. **Installing PrinceXML**\n\n    bookpub uses princexml (an advanced PDF typesetting library) in its built-in pdf stage\n    * (You can easily use something else, by visiting the [Overriding or Adding Stages](#overriding-or-adding-stages) section)\n\n    Please visit the [PrinceXML Installation Page](https://www.princexml.com/doc/12/doc-install/) for directions on installing Pandoc on your operating system\n\n---\n\n## Installation\n\n```bash\n# Option 1: Install globally\nnpm install -g bookpub\n```\n\n---\n\n## Quick Start\n\n1. **Create a new Bookpub project**:\n   ```bash\n   bookpub new my-book\n   ```\n   This scaffolds a folder `my-book/` with all necessary boilerplate.\n\n3. **Build a PDF**:\n   ```bash\n   cd my-book\n   bookpub build html\n   ```\n   The output is in `build/html/`.\n\n4. **Open** `manuscript/index.md.ejs` to write your content, or **customize** `book.config.yml` with your book’s metadata and pipelines/stages.\n\n---\n\n## Project Structure\n\nWhen you create a new Bookpub project (e.g. `my-book/`), you’ll typically see:\n\n```\nmy-book/\n├── .gitignore\n├── README.md\n├── book.config.yml\n├── manuscript/\n│   ├── index.md.ejs\n│   └── themes/\n|       └── default/\n│           ├── css/\n│           │   ├── styles.pdf.scss\n│           │   └── styles.epub.scss\n│           ├── images/\n│           └── ...\n├── stages/\n├── package.json\n└── ...\n```\n\n- **`book.config.yml`**: Central config for metadata, pipeline definitions, etc.\n- **`manuscript/`**: The source files for your book.  \n  - `index.md.ejs` is your main entry point, combining EJS + Markdown.  \n  - `themes/` holds SCSS/CSS, images, fonts, etc.\n- **`stages/`**: (Optional) Put custom stages or override existing ones here.  \n- **`package.json`**: The project’s local dependencies (including `bookpub`).\n\n---\n\n## Using Pipelines or Stages\n\n### Default Pipelines \u0026 Stages (`book.config.yml`)\n\nBookpub comes with a couple pipelines pre-defined for `html` and `pdf` that have pre-built stages (_all of which you can override_):\n\n```yaml\nbuildPipelines:\n  html:\n    stages:\n      - name: ejs\n      - name: markdown\n      - name: themes\n      - name: writeHtml\n\n  pdf:\n    stages:\n      - name: ejs\n      - name: markdown\n      - name: themes\n      - name: writeHtml\n      - name: pdf\n```\n\nNow `bookpub build pdf` will run the pdf build-pipeline and execute these stages in order: `ejs \u003e markdown \u003e themes \u003e writeHtml \u003e pdf `.\n\n### Defining Custom Pipelines in `book.config.yml`\n\n```yaml\n# book.config.yml\n\nglobal: # Applied globally to all pipelines\n  meta:\n    title: \"My Book\"\n    author: \"Famous Name\"\n  stages:\n    - name: ejs # Applied to all ejs stages in every pipeline\n      config:\n        rmWhitespace: true\n\nbuildPipelines:\n  pdf-lg: # A custom pipeline for a large font pdf\n    meta:\n      title: \"My Book (Large Print)\" # Overrides global meta\n      fontSize: 18\n    stages:\n      - name: ejs\n        config: # Overrides global settings for thie pipeline\n          rmWhitespace: false\n      - name: markdown\n      - name: theme\n      - name: writeHtml\n      - name: pdf\n        config:\n          lineSpacing: 1.5\n```\n\nNow `bookpub build pdf-lg` will run the pdf-lg build-pipeline and execute these stages in order: `ejs \u003e markdown \u003e themes \u003e writeHtml \u003e pdf `.\n\n---\n\n## Working With Meta\n\nYour `file.md.ejs` can reference metadata from `book.config.yml` like this:\n\n```markdown\n# \u003c%= meta.title %\u003e\n\nAuthor: \u003c%= meta.author %\u003e\n\nThis is dynamic EJS. If you specify `meta.title` in `book.config.yml`,\nit appears here at build time.\n```\n\n1. **global** `meta` applie to **all** builds.  \n2. **Pipeline-specific** `meta` (defined under a pipeline) override global values for that build only.\n\n---\n\n## Overriding or Adding Stages\n\n### Overriding a Pre-Built Stage\n\nIf you want to modify bookpub's pre-built **ejs** stage (for example), just create a matching folder in your project:\n```\nmy-book/\n└─ stages/\n   └─ ejs/\n      └─ index.js\n```\nInside `index.js`, export a `run()` function:\n\n```js\n// my-book/stages/ejs/index.js\nexport async function run(manuscript, { stageConfig, globalConfig }) {\n  // Your custom logic\n  // e.g., call the built-in ejs stage, then do extra stuff\n  // or replace it entirely\n  return manuscript;\n}\n```\n\nBookpub automatically detects `stages/ejs/index.js` and uses it **instead** of the pre-built EJS stage.\n\n### Creating a New Stage\n\nJust name a folder in `stages/` (e.g., `stages/compressImages/`) with an `index.js`:\n\n```js\n// my-book/stages/compressImages/index.js\nexport async function run(manuscript, { stageConfig, globalConfig }) {\n  console.log(\"Compressing images...\");\n  // do your stuff\n  return manuscript;\n}\n```\n\nThen add it to a pipeline in `book.config.yml`:\n\n```yaml\nbuildPipelines:\n  pdf:\n    stages:\n      - name: ejs\n      - name: compressImages\n      - name: markdown\n      - name: theme\n```\n\nHere's an example explanation you can include in your README.md under a \"Developing Custom Stages\" section. This explanation details the API that each stage must follow—specifically, the requirements for the exported `run()` function and its parameters: `manuscript`, `stageConfig`, and `globalConfig`.\n\n---\n\n### Developing Custom Stages\n\nBookpub's modular design allows you to extend or replace any stage by creating a new module. Each stage is expected to expose a single asynchronous function named `run()`. When Bookpub executes a build pipeline, it will call the `run()` function for each stage, passing in three key parameters:\n\n- **`run()` Function**  \n  This is the entry point for your stage. It must be an asynchronous function (or return a Promise) so that the build pipeline can wait for it to complete its work before proceeding to the next stage. For example:\n  \n  ```js\n  export async function run(manuscript, { stageConfig, globalConfig }) {\n    // Your custom stage logic here\n    return manuscript;\n  }\n  ```\n\n- **`manuscript` Object**  \n  This object represents the current state of the manuscript and is passed from one stage to the next. It typically contains:\n  \n  - `manuscript.content`: The manuscript content (e.g., rendered Markdown or HTML). Each stage can read or modify this property.\n  - `manuscript.buildType`: The current build type (e.g., `'html'`, `'pdf'`, etc.), which might affect how the stage processes the content.\n  \n  Your stage should update and then return the modified `manuscript` so that subsequent stages can work with the latest version.\n\n- **`stageConfig` Object**  \n  This object contains configuration options specific to the current stage. It is built by merging any global defaults (from `global.stages` in `book.config.yml`) with pipeline-specific overrides. It is typically structured as follows:\n  \n  ```js\n  {\n    config: {\n      // Stage-specific configuration options go here.\n      // For example, for the built-in EJS stage:\n      rmWhitespace: true\n    },\n    meta: {\n      // Optional stage-specific metadata.\n    }\n  }\n  ```\n  \n  Use `stageConfig.config` to access options for your stage. For example, if you’re building a custom image compressor, you might include options such as `quality` or `maxWidth` in this object.\n\n- **`globalConfig` Object**  \n  This object contains configuration and metadata that apply to every stage. Typically, it includes:\n  \n  ```js\n  {\n    meta: {\n      // Global metadata such as title, author, publication date, etc.\n      title: \"My Awesome Book\",\n      author: \"John Doe\",\n      ...\n    }\n  }\n  ```\n  \n  This allows your stage to access universal information about the book, regardless of its own specific configuration.\n\nBy following this API, you ensure that your custom stage can be seamlessly integrated into Bookpub's build pipeline. Developers can add new functionality or override existing stages simply by creating a folder under `/stages/` with the same name as the stage they want to replace. Bookpub will automatically use your custom implementation.\n\n## Build Outputs\n\nBy default, Bookpub outputs to:\n```\nbuild/\u003cbuildType\u003e/\n```\nFor example:\n```\nbuild/html/\nbuild/pdf/\nbuild/pdf-lg/\n```\nThat folder might include:\n- **index.html** (or whatever each stage produces)\n- **themes/** (copied or compiled assets)\n- Final PDF, EPUB, or other output generated by custom stages\n\n---\n\n## Pandoc Markdown Tutorial\n\nThis tutorial demonstrates how Pandoc converts extended Markdown into HTML. We’ll cover:\n\n- General Markdown\n- Fenced code blocks and attributes\n- Link attributes\n- Bracketed spans\n- Generic attributes\n- Raw attributes\n- How to designate specific HTML tags: section, article, footer, div, span, pre, code, br, hr\n\n---\n\n### 1. General Markdown\n\nBasic Markdown elements work as you’d expect. For example:\n\n```markdown\n# Sample Heading\n\nThis is a paragraph with **bold text** and *italic text*.\n\n- List item 1\n- List item 2\n```\n\nPandoc converts that into:\n\n```html\n\u003ch1\u003eSample Heading\u003c/h1\u003e\n\u003cp\u003eThis is a paragraph with \u003cstrong\u003ebold text\u003c/strong\u003e and \u003cem\u003eitalic text\u003c/em\u003e.\u003c/p\u003e\n\u003cul\u003e\n  \u003cli\u003eList item 1\u003c/li\u003e\n  \u003cli\u003eList item 2\u003c/li\u003e\n\u003c/ul\u003e\n```\n\n---\n\n### 2. Fenced Code Blocks and Attributes\n\nPandoc supports fenced code blocks with extra attributes to set language, id, classes, etc.\n\n```markdown\n    ```python {#code-example .highlight}\n    def greet():\n        print(\"Hello, world!\")\n    ```\n```\n\nThis tells Pandoc to wrap the code in a `\u003cpre\u003e` and `\u003ccode\u003e` block, add an `id` of `code-example`, a class `highlight`, and also a language class for syntax highlighting:\n\n```html\n\u003cpre id=\"code-example\" class=\"highlight\"\u003e\n  \u003ccode class=\"language-python\"\u003edef greet():\n    print(\"Hello, world!\")\n  \u003c/code\u003e\n\u003c/pre\u003e\n```\n\n---\n\n### 3. Link Attributes\n\nYou can attach extra attributes to links. Check out this example:\n\n```markdown\n[Visit Google](https://google.com){: target=\"_blank\" class=\"external-link\"}\n```\n\nPandoc converts it into:\n\n```html\n\u003cp\u003e\u003ca href=\"https://google.com\" target=\"_blank\" class=\"external-link\"\u003eVisit Google\u003c/a\u003e\u003c/p\u003e\n```\n\n---\n\n### 4. Bracketed Spans\n\nBracketed spans let you add attributes to inline elements. For instance:\n\n```markdown\nThis is a [highlighted text]{.highlight} within a sentence.\n```\n\nResults in:\n\n```html\n\u003cp\u003eThis is a \u003cspan class=\"highlight\"\u003ehighlighted text\u003c/span\u003e within a sentence.\u003c/p\u003e\n```\n\n---\n\n### 5. Generic Attributes\n\nGeneric attributes work on block-level elements like headings or paragraphs. For example:\n\n```markdown\n# A Titled Section {.section-title}\n\nSome paragraph text with a generic attribute.\n```\n\nConverts to:\n\n```html\n\u003ch1 class=\"section-title\"\u003eA Titled Section\u003c/h1\u003e\n\u003cp\u003eSome paragraph text with a generic attribute.\u003c/p\u003e\n```\n\n---\n\n### 6. Raw Attributes\n\nRaw HTML in your Markdown is passed through as-is, including its attributes. For example:\n\n```markdown\n\u003cdiv data-info=\"raw\" style=\"color: red;\"\u003e\n  This is a raw HTML block with attributes.\n\u003c/div\u003e\n```\n\nPandoc leaves it untouched:\n\n```html\n\u003cdiv data-info=\"raw\" style=\"color: red;\"\u003e\n  This is a raw HTML block with attributes.\n\u003c/div\u003e\n```\n\n---\n\n### 7. Designating Specific HTML Tags\n\nPandoc’s Divs (and inline spans) let you specify a custom HTML tag by using the `tag` attribute.\n\n#### Section\n\n```markdown\n::: {tag=section #sec1 .intro}\nThis content is inside a \u003ccode\u003esection\u003c/code\u003e element.\n:::\n```\n\nBecomes:\n\n```html\n\u003csection id=\"sec1\" class=\"intro\"\u003e\n  \u003cp\u003eThis content is inside a \u003ccode\u003esection\u003c/code\u003e element.\u003c/p\u003e\n\u003c/section\u003e\n```\n\n#### Article\n\n```markdown\n::: {tag=article #article1 .post}\nContent inside an \u003ccode\u003earticle\u003c/code\u003e element.\n:::\n```\n\nConverts to:\n\n```html\n\u003carticle id=\"article1\" class=\"post\"\u003e\n  \u003cp\u003eContent inside an \u003ccode\u003earticle\u003c/code\u003e element.\u003c/p\u003e\n\u003c/article\u003e\n```\n\n#### Footer\n\n```markdown\n::: {tag=footer #footer1}\nFooter content goes here.\n:::\n```\n\nBecomes:\n\n```html\n\u003cfooter id=\"footer1\"\u003e\n  \u003cp\u003eFooter content goes here.\u003c/p\u003e\n\u003c/footer\u003e\n```\n\n#### Div\n\nA standard Div (without overriding the tag) remains a `\u003cdiv\u003e`:\n\n```markdown\n::: {#div1 .container}\nContent inside a div.\n:::\n```\n\nConverts to:\n\n```html\n\u003cdiv id=\"div1\" class=\"container\"\u003e\n  \u003cp\u003eContent inside a div.\u003c/p\u003e\n\u003c/div\u003e\n```\n\n#### Span\n\nBracketed spans by default yield `\u003cspan\u003e` elements. For example:\n\n```markdown\nHere is an [inline span]{#span1 .highlight} in a sentence.\n```\n\nResults in:\n\n```html\n\u003cp\u003eHere is an \u003cspan id=\"span1\" class=\"highlight\"\u003einline span\u003c/span\u003e in a sentence.\u003c/p\u003e\n```\n\n#### Pre and Code\n\nFenced code blocks (as shown earlier) automatically produce `\u003cpre\u003e` and `\u003ccode\u003e` blocks.\n\n#### Line Break (br)\n\nA hard line break can be made by ending a line with two spaces:\n\nFirst line with a hard break.  \u003c-- Two Spaces\n```markdown\nSecond line continues.\n```\n\nThis converts to:\n\n```html\n\u003cp\u003eFirst line with a hard break.\u003cbr /\u003e\nSecond line continues.\u003c/p\u003e\n```\n\n#### Horizontal Rule (hr)\n\nA horizontal rule is simply three or more hyphens:\n\n```markdown\n---\n```\n\nWhich becomes:\n\n```html\n\u003chr /\u003e\n```\n\nThis code is licensed under the C-MIT (Caffeinated-MIT) License","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fworlduniting%2Fbookpub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fworlduniting%2Fbookpub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fworlduniting%2Fbookpub/lists"}