個人出版・AI校正

CSS組版VivliostyleはMarkdownでPDF変換におすすめ!?【VSCode】

個人出版・AI校正

電子書籍作成のために、PDFとePUBが作成できるvivliostyleの覚書です。現在は簡単に導入できます。

技術同人誌のまとめ記事はこちらです。

目次

CSS組版Vivliostyleのおすすめ本

いつのまにか本がでていました。購入したところひととおりテクが紹介された丁寧な本という感じです。

著:Vivliostyle, 著:リブロワークス
¥3,376 (2024/03/09 16:46時点 | Amazon調べ)
スポンサーリンク

CSS組版VivliostyleのVSCodeで環境構築

vivliostyleのインストール

まず、vivliostyleのローカルリポジトリを作成しましょう。VS Codeを使っています。

  1. vivliostyle-booksというフォルダを作成する(このフォルダに本を入れていきます)
  2. File > New Windows
  3. File > Add workspace folderでフォルダの位置を紐づける

node.jsがインストールされているか確認。インストールされていない場合、インストールが必要

node -v

インストールします。

npm install -g @vivliostyle/cli

確認します。

vivliostyle --version

VsCode内にテンプレートを作ります。Pandocと一緒に併用しても問題なさそうです。

npm create book pdfbook

最後は本の名前で必須のようです。指定しないとエラーがでます。

npm create book bookname
Ok to proceed? (y) y
? description description
? author name neru
? author email
? license MIT
? choose theme @vivliostyle/theme-techbook - Techbook (技術同人誌) theme

descriptionは書いてもいいけど、そのままenter。

emailはちょっとよくわからず指定しませんでした。

MACのfinderでファイルを確認したい場合は次のコマンドです。

open .

のちのち画像ファイルなどを確認する際によく使うため覚えておくとよいでしょう。

vivliostyleでpdf作成

ディレクトリを移動してビルド。

cd pdfbook
npm run build

初回のビルド時間はやや長いです。ビルドすると初回にnode_modulesが勝手に作成されます。

またHtmlとPDFが生成されます。

以上でできあがりです。

ここでおしまいにすると簡単に終わってしまったため、もう少し設定を解説していきましょう。

npm run dev –prefix pdfbook

cdでいちいち移動するのが面倒という人もいるでしょう。

npm runコマンドに--prefixオプションを指定することで、サブディレクトリ内のpackage.jsonファイルに定義されているスクリプトを実行することができます。

npm run dev --prefix pdfbook
スポンサーリンク

MarkdownでPdf変換におすすめなCSS組版Vivliostyle

本のサイズ

サイズの設定も重要です。1ページに入るコードや画像の入り方が変わります。紙の書籍なら小さい方が持ち運びが便利などあるかもしれませんが、電子書籍は多少大きめの方が見やすいかもしれません。

A4でもよかったのですが、本っぽいB5にしました。A5はソースコードが中途半端に区切られたり、1ページに画像1枚しか入らなかったりしたため、やめました。面積が小さい気がします。

size: 'B5', // paper size.

A4よりB5の方が当然、ページ数を増やせます。58ページ→68ページになりました。

エクスポート

  output: [
    {
      path: './ebookbrain book.pdf',
      format: 'pdf',
    },

cssとmdファイルを割り当てを変更

cssとmdファイルを割り当てを変更する方法です。同フォルダにsample.mdとsample.cssを作成し、次のように書き換えるだけです。

theme: 'sample.css',
entry: [
  'sample.md',
],

ただし、実際はテーマを割り当て別途CSSを使う方法になりそうです。

テーマの作り方

テーマに直接CSSを割り当てました。

しかし、フォントなどいろいろなものを管理する場合、任意の名前のフォルダ(今回はtheme-original)を作成してそのフォルダ名を指定する方法があります。テーマごとに管理する場合はこの方が便利です。

theme: 'theme-original',

階層を’@vivliostyle/theme-original’とするとうまくいきません。

theme-originalのフォルダ内にpackage.jsonを作ります。次のような指定をします。

{
  "name": "theme-original",
  "main": "main.css"
}

originalthemeのディレクトリ内に、CSSファイル(メインのCSSファイルからimportする他のCSSファイル)、画像、フォントファイルなどを入れることができます。

nameは規約的に大文字禁止です。

このような状態でbuildすると、thme: に指定したディレクトリが丸ごと.vivliostyle/themes/packages/ の下にコピーされるようです。

npm run buildはvivliostyle.config.jsがある直下で実行します。

ヘッダーとページ数の入れ方

@page {
    @top-center {
        content: "ヘッダー";
    }
    @bottom-center {
        content: counter(page) " / " counter(pages);
    }
}

どのような配置ができるのか仕様は次とおりのようです。

ページヘッダー/フッターを指定する@top-center@bottom-centerなど(ページマージンボックスという)は CSS Paged Media 仕様で次の 16 個が定義されています。

https://vivliostyle.github.io/vivliostyle_doc/ja/vivliostyle-user-group-vol1/shinyu/index.html

変数を使うと、もっと応用的なこともできます。

表紙のサイズ

vivliostyle.config.jsで指定された画像のサイズを用意します。ただし、微妙にあわないことがあります。

marginおよび画像サイズを微妙に調整します。3mm下に足しました。

@page :first {
  background-color: #626262;
  margin: -4mm -2mm;
  padding-top: 4px;

  /* 表紙ページはページヘッダー/フッター無し */
  @top-left { content: none; }

  @top-right { content: none; }

  @bottom-center { content: none; }
}

ただし、画像サイズが大きいと2ページ目に画像が落ちてしまうので、注意しましょう。Webのカラム落ちのようなものです。

cover.mdを作成して、画像を貼るコードを一行追加するだけです。

![](theme-original/images/cover.png)

必要ならサイズ調整しましょう。

![](theme-original/images/cover.png){width=100%}

オリジナル画像を作るならテーマの中で画像を管理するとよいでしょう。

とびらページ

最初のページだけ背景色を付けたい場合はこうですが、これだと表紙だけに色がつきます。

@page:first {
  margin: 0;
  background-color: blue;
}

とびらページは章ごとにMarkdownファイルをわけるとよいです。そして@page :nth(1)を使います。2色分けしたい場合はlinear-gradientを使います。

追記:久々にvivliostyleを試したら@page :nth(1)は構文エラーがでるようです…。別のアプローチに変えました。

@page :nth(1) {
  margin: 0;
  background: linear-gradient(to right, white 80%, #f3eacb 20%);
}

個別に色分けしたい場合は個別にh1タグにClassをつけます。

CSS組版でいろいろデザインしたい場合はdivタグで囲うとよいでしょう。

<div class="doorpage1">
  <h1>プログラムの話</h1>
  <div class="doorpage-en-title">program story</div>
</div>
@page doorpage1 {
  background: linear-gradient(to right, white 80%, #f3eacb 20%);
  margin: 0;
}

.doorpage1 {
  page: doorpage1;
  position: relative;
}

.doorpage-en-title {
  position: absolute;
  top: 50px;
  right: 50px;
  transform-origin: top right;
  transform: translate(-20px, 150px) rotate(90deg);
  font-size: 80px;
  color: #c4af8f;
}

はしら

はしらとは、本の上や右に表示した章や節のタイトルです。

content: env(doc-title);

どうやらCSS Generated Content for Paged Media Module Level 3(CSS GCPM 3)の仕様が元になっているようです。

索引(ツメ)

最初、SCSSでこんなことできないのかなと思ったのですが、

@for $i from 1 through 10 {
  @page :nth(#{$i}) {
    @top-right {
      content: "Chapter 1";
    }
  }
}

@for $i from 11 through 20 {
  @page :nth(#{$i}) {
    @top-right {
      content: "Chapter 2";
    }
  }
}

@page :nthはなぜか構文エラーがでてしまいました。公式サイトにもそういう記述あるのですが、改善方法があるのなら教えてもらいたいところです。

そこでやり方を変えました。string-setを使う方法が本で紹介されていましたが、position: runningを使う方法を採用しました。

お試しでヘッダーに表示してみます。

<div class="sideindex top1"><span class="sideindex-number">1</span>テスト</div>
@page: right {
  @top-right {
    content: element(sideindex);
  }
}

.sideindex {
  position: running(sideindex);
}

ただ索引はサイドにだすのが一般的なので、コードを変更します。

@page: right {
  @right-top {
    content: element(sideindex);
    writing-mode: vertical-rl;
  }
}

仮の目次の作り方

最初、1つのmdファイルで執筆していきました。

その際、現状把握のため目次を作る拡張があると便利です。

いくつかでていますが、最終的にmarkdown all in oneを使いました。あくまで仮の目次を作成するものです。

  1. 使い方はコマンドパレットでtableやmarkdownと打つ
  2. Markdown All in One: Create Table of Contentsを選ぶと目次を生成
  3. 保存すれば自動的に目次は更新される

ただ、これは執筆中にどんな項目があったのか自分用に把握するためのものです。1つのmdファイルを把握するのに役立ちます。

本番では消します。

8割型できたあとで、mdファイルをわけました。この辺りは好みで最初からきちんとわけてもよいでしょう。

vivliostyleの目次を自動化するにはスクリプトが必要だった件

toc.mdを作成してvivliostyleの目次を作成します。cssも必要です。

しかし、この作業はプログラマならダルいと思いがち…。

<nav id="toc" role="doc-toc">

## 目次

### Part1 ●●編

- [リンク1](1-01.html)
- [リンク2](1-02.html)

### Part2 ●●編

- [著者](colophon.html)

</nav>

<nav role="doc-toc"> … </nav> で囲むブロック内に目次項目(本文中の各見出しへのリンク)のリストを入れます。

https://vivliostyle.org/ja/faq/#%E7%9B%AE%E6%AC%A1%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%AB%E3%81%AF

目次の自動作成も一応あるのですが、デフォルトでは微妙です。

目次の手動作成

Vivliostyle の機能を使って作られる目次には、現状、各原稿ファイルのタイトルしか表示できません。したがって、例えば原稿ファイルの各見出しを目次に表示したい場合は、手動で目次ファイルを作成する必要があります

https://vivliostyle.org/ja/tutorials/create-table-of-contents/

ちなみに、中扉に目次を挟みましたけど、それは効かなかったです。。

結論をいえばちゃんと作った方がよいということになり、手動がしんどいので、nodejsで別途スクリプトを書きました…。

Vivliostyle Docsのドキュメントが1番参考になりました。マニフェストファイルの理解が必要そうです。publication.jsonを作らないとリンクが機能しません。リンクが機能しないと、ページ数が表示されない状況にもなります。

目次の作り方については W3C Publication Manifest 仕様に付属の Machine-Processable Table of Contents を参照してください。

https://docs.vivliostyle.org/#/ja/vivliostyle-cli#%E7%9B%AE%E6%AC%A1%E3%81%AE%E4%BD%9C%E6%88%90

3つスクリプトが必要でした。

  • 見出しにIDをつける
  • 目次を自動生成する
  • publication.jsonを設定してビルドする

vivliostyleの目次のページ数が表示されない!?

目次のページ数を表示するだけなら、CSSに次のようなコードをかけばいけます。

#TOC li a::after {
  content: target-counter(attr(href), page);
}

しかし、目次をちゃんと作っていないと??と表示されるだけで番号を取得してくれません。

目次の点線は`leader(dotted)`を追加します。leader(dotted)はあっという間に目次っぽくなるため、ちょっと感激しますね。

#TOC li a::after {
  content: leader(dotted) " " target-counter(attr(href), page);
}
  • leader(dotted): リーダー(leader)は繰り返し表示される文字やパターンのことです。点線(dotted)のリーダーを指定しています。
  • attr(href): リンクのhref属性の値を取得します。
  • page: ページカウンターの値を表示するように指定します。つまり、リンク先の要素が存在するページ番号を表示します。

コードブロック(highlight.js,prism.js)

デフォルトのままではスタイルはないため、スタイルを用意する必要があります。調べたらprism.jsに対応しているようです。highlight.js,は公式サイトに記載がありませんでした。

ソースコードのシンタックスハイライトには Prism.js が使えます。

https://vivliostyle.org/ja/tutorials/configure-basic-elements/

JavaScriptが使えるようになり、Chart.jsなども利用できるぽいです。

JavaScriptが使えるようになりました

https://vivliostyle.org/ja/blog/2022/01/24/JavaScript-can-now-be-used-in-typesetting-by-Vivliostyle/

prism.jsの使い方はこちらです。

スポンサーリンク

CSS組版Vivliostyleで執筆環境の自動化

文章の校正を自動化するtextlintの導入

VS Codeを利用するなら文章の校正が自動でできるtextlintを導入しましょう。詳しくはこちらの記事にまとめました。

CSSを自動修正するstylelint

CSS組版なのでCSSをかきます。CSSを自動修正するstylelintが入っているとあとあと楽でしょう。

スポンサーリンク

CSS組版VivliostyleのFAQ

vivliostyleはepubの作成はできるの?

案内がありました。

ただ個人的にHTMLとePUBはテンプレートを利用しています。

create-book と CLI の関係

create-bookをインストールすると、CLI は勝手に最新版がインストールされるようです。

"@vivliostyle/cli": "latest",

CLIをインストールすると、vivliostyle系のコマンドが使えるようになるはずです。

vivliostyle: command not found

vivliostyle系のコマンドがエラーになります。

book $ vivliostyle preview 1-00.md
bash: vivliostyle: command not found

解決方法は次のとおりです。

vivliostyle preview

公式サイトに記載がなかったのですが、textlintみたくnpxをつけないとダメみたいですね。このコマンドでプレビューできます。

book $ npx vivliostyle preview 1-00.md
🚀 Up and running ([ctrl+c] to quit)
✔ Built images/test.jpg

主にGoogleによって開発とメンテナンスが行われているChromium(クロミウム)が起動します。

mdファイル以外もできるようです。

vivliostyle preview index.html
vivliostyle preview https://example.com –user-style my-style.css
vivliostyle preview publication.json
vivliostyle preview epub-sample.epub –user-style my-style.css
vivliostyle preview manuscript.md –theme my-theme/style.css

https://docs.vivliostyle.org/ja/vivliostyle-cli

Macはうまくいったのですが、

ただし、Windowsではエラーがでてうまくいきませんでした。Chromiumが入っていないのかな??Mac中心なので詳しくは調べていません。

npm ERR! could not determine executable to run
npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\horot\AppData\Local\npm-cache\_logs22-08-14T06_06_59_790Z-debug-0.log

執筆初期の頃はMarkdown Preview Enhancedの方がちょっとお手軽な感じもするので併用しています。

Vscodeの文字数のカウント

VSCodeの拡張があります。日本人開発のCharacterCountです。

CharacterCount - Visual Studio Marketplace

作者の説明はこちらです。

小説家のためのVisual Studio Code 拡張機能を作成しました - Qiita

他にも小説用の拡張はいくつかでていて文字数のカウントはできるようです。

vivliostyleのアップデート(バージョンを確認)

普通ですね。npxが必要です。

npm outdated
npm install @vivliostyle/cli@latest
npx vivliostyle -v

vivliostyleのpdfのサイズが違う

最新版にしたところ、PDFのサイズが正しく書き出されなくなりました。A4じゃないのにA4っぽくなる。。ダウングレードしたらなおりました。4.8.2は安定運用できています。

npm remove @vivliostyle/cli
npm install @vivliostyle/cli@4.8.2
npx vivliostyle -v

Vscodeのアウトライナー

本を執筆するとなるとよく前後の順番でを入れ替える作業をします。

VsCodeは左のエクスプローラーに、アウトライナー機能を実はデフォルトで持っています。しかし、順番を入れ替えることができません。

ただし、秀丸のアウトライナーならできるため、コピペで貼り付けて入れ替えて元に戻すみたいな作業はしてもいいかもです。2つのソフトを跨ぎますが、コピペは一瞬なので。やっぱり秀丸は優秀。

秀丸はWindowsのソフトです。個人的にMacとWindowsのハイブリット環境のためいいのですけど。

VsCodeのアウトライナーの拡張は調べたのですが、それっぽいものは見当たりませんでしたね。順番を入れ替えられる方法があったら教えてほしいです。

スポンサーリンク

CSS組版VivliostyleとPandocを併用する

個人的にePUBとHtmlはPandocを使っています。PandocでPDFを制御するのはLaTeXを使わらなければならず、LaTeXよりCSS組版の方が簡単です。また、PandocからWordに変換してPDFを出力する方法はスタイルが自動で適用することが難しく、Word側の作業が発生します。そこで、このようなすみわけになりました。

  • Pandoc:HtmlとePUB
  • Vivliostyle:PDF

どうやらひとつのプロジェクトで併用しても問題がなさそうです。

Vivliostyleはmybook内にnode_modulesを作るようです。Pandocはルートディレクトリです。そのため2つになってしまいますが、弊害はなさそうです。Vivliostyle的にたぶんそこに作るようにした意図もあるでしょうし。

この件はAIのclaude opus君とも相談しました。以下、claudeの君の意見です。node_modulesを分けることには、メリットとデメリットがあります。

メリット:

  1. 依存関係の分離:各ツールが必要とするパッケージを個別に管理できるため、依存関係の衝突を避けられます。
  2. バージョンの違い:同じパッケージでも、ツールごとに必要なバージョンが異なる場合に対応できます。
  3. 互換性:ツール間の互換性の問題を回避できます。

デメリット:

  1. 容量の増大:重複するパッケージがある場合、ディスク容量を余分に消費します。
  2. 管理の複雑さ:node_modulesが複数あると、管理やメンテナンスがやや複雑になります。

ただし、現代のプロジェクト管理ツール(npmやyarnなど)は、重複するパッケージを可能な限り共有するようになっています。これにより、容量の増大は最小限に抑えられます。

また、ツールごとにnode_modulesを分けることは、一般的な慣習でもあります。それぞれのツールが独立して動作することを保証し、互いの依存関係による問題を回避するためです。

したがって、特に大きな問題がない限り、node_modulesを分けて管理するのが無難だと思います。

VivliostyleはHtmlに変換ののち、PDFを作成しているぽい

Vivliostyleで変換すると、mdファイルと一緒のところにhtmlファイルができるのですね。調べたら、Htmlに変換ののち、PDFを作成しているぽいですね。

  1. MarkdownをHTMLに変換する(VFM)
  2. スタイルを切り替える(Themes)
  3. 複数の原稿から本の形にまとめる
  4. HTMLとCSSを処理し、ページに組み立てる(Vivliostyle.js)
  5. CSS組版の結果をプレビューする(Vivliostyle Viewer)
  6. PDFとEPUBを出力する
https://gihyo.jp/article/2024/01/vivliostyle-01

VivliostyleのMarkdownの仕様

基本はCommonMark をもとにということでしょうか。

Markdown は標準仕様を定めていない。そのため方言が乱立していた。この事態を問題視した人たちにより CommonMark が生み出される。現在の GFM もこれに基づいており、仕様の冒頭で以下のように宣言している。

https://vivliostyle.github.io/vivliostyle_doc/ja/vivliostyle-user-group-vol3/akabeko/index.html

テストしたところ、Pandocでは効くのに、Vivliostyleでは効かない記法もあるようです。

[イエローのマーカー]{.marker}です。←効かない

htmlで無難に書くとよさそうです。

<span class="marker">イエローのマーカーです。</span>
スポンサーリンク

Vivliostyleで作成した電子書籍をgithubで管理する

あらかじめリポートリポジトリの作成をしておきます。git remote add originのパスは作成した<span class=“marker”>イエローのマーカーです。</span>

git --version // macの場合、gitはデフォルトで入っています。
git init // その位置をルートディレクトリとし、gitの隠しファイルが作成される。必要ならその前にcdで移動
git remote add origin https://github.com/username/progectname
git remote -v  // パスの確認
git push -u origin master //add、コミットしたのち、次のコマンド

githubの使い方はこちらの記事を参考にしてください。

md、vivliostyle.config.js、package.jsonなどはGithub管理にします。

vivliostyleでgitignoreがない!node_modules/の除外

git pushしようと思ったらpush対象がすごい。

node_modules/まで対象になっていたため除外します。

.gitignoreという空ファイルを作成。

.gitignoreはgithubの管理外のファイルを指定するものです。自動生成されたファイルなどは管理しなくても平気です。
node_modules/
themes/
*.html
*.pdf

作成する際にディレクトリがあっていないと除外されないため作る場所を確認しましょう。

テーマはオリジナルで用意するため除外しています。

.gitignore自体は除外せずpushした方がよいでしょう。編集者とチーム開発しているなら共有物とした方がよさそうです。stackoverflowなどを参考にしましょう。

The .gitignore file’s purpose is to prevent everyone who collaborates on a project from accidentally commiting some common files in a project, such as generated cache files. Therefore you should not ignore .gitignore, since it’s supposed to be included in the repository.

https://stackoverflow.com/questions/10176875/add-gitignore-to-gitignore/
スポンサーリンク

Vivliostyleのエラー

✖ Error: Cannot set property ‘end’ of null

mdファイルの中身がおかしいとこけるようです。

(node:36546) ExperimentalWarning: The fs.promises API is experimental
◡ Collecting build config(node:36547) ExperimentalWarning: The fs.promises API is experimental
✖ Error: Cannot set property 'end' of null

If you think this is a bug, please report at https://github.com/vivliostyle/vivliostyle-cli/issues
npm ERR! code ELIFECYCLE
npm ERR! errno 1

フォントエラー

CSSファイルのフォントファイルがないとビルドは通りますが、次のようなエラーがでました。

(node:37639) ExperimentalWarning: The fs.promises API is experimental
◡ Collecting build config(node:37640) ExperimentalWarning: The fs.promises API is experimental
✖ 404 http://localhost:13000/themes/assets/fonts/hannari/Hannari.woff2
✖ 404 http://localhost:13000/themes/assets/fonts/hannari/Hannari.woff

ひとまず最低限の文字にしてみましょう。

Error: ENOENT: no such file or directory

ビルド時にでます。

Error: ENOENT: no such file or directory

このエラーは簡単です。単にファイルがないだけです。

ファイルをリネイムしたとき、うっかりvivliostyle.config.jsを修正し忘れるとでます。リネイムしたとき、不要なHtmlファイルも削除します。

この状態でVS Codeを保存しようとするとワークスペース を設定しますか?みたいなおかしな状態になるため注意しましょう。

vivliostyle: Permission denied

sh: /Users///book/node_modules/.bin/vivliostyle: Permission denied

previewする際にでるようになって、ちょっと原因不明だったのですが、バージョン違いの他のプロジェクトが実行できたため、最新版にアップデートしたら改善しました。

Error: EBUSY: resource busy or locked, open

✖ Error: EBUSY: resource busy or locked, open

ビルドする際にAdobe Acrobatが開いているとダメのようです。PDFをAcrobatで開かないようにした方がよいかもしれません。ChromeでPDFを開くと、少なくともこのエラーがでないため。

このエラーがでたとき、うまくクリアされない場合があるようです。VsCodeやCursorを再起動したらなおります。

exec error: Error: Command failed: npm run build –prefix pdf

Vivliostyleは開いているPDFを閉じずに、次のPDFを作成しようとするとエラーがでるようです。

exec error: Error: Command failed: npm run build --prefix pdf
スポンサーリンク

Vivliostyleの事例

このかたはVivliostyleですね。

参考になれば幸いです。

スポンサーリンク
neruをフォローする
スポンサーリンク

コメント

タイトルとURLをコピーしました