ファイル操作

Web

Node.jsでHTMLファイルを大量制作

手動で大量制作されたHTMLを新たなテンプレートで制作し直すことになりそうだったので、それを手軽にできないか調べた時の話。発見があったので、メモ。このままいくと、手作業で全ファイル作り直す羽目になるかもしれない。だが、それは嫌。全部とは言わずとも、少しは楽になる手段はないかと調べると出てきたのがNode.jsです。数年前から、expressだったり、gulpだったりで、楽ができるNode.jsが気になっていました。インストールだけして、ほったらかしだったのですが、ここ最近前述のjsを使ってみると、驚くほど手軽に作業できることがわかりました。そして、デスクトップアプリケーションとしても利用できるんだとか。なんだか凄く便利な予感。

Node.js — Run JavaScript Everywhere
Node.js® is a JavaScript runtime built on Chrome's V8 JavaSc…

そこで既存のHTMLから必要な情報を抜いて、新しいテンプレートにコピーして、任意の名前で保存すればいいんじゃないかと考えました。具体的には、2つのHTMLファイルから特定部分をそれぞれ抜き、テンプレートファイルに追加して、片方のHTMLファイルと同じ名前で保存します。調べると結構情報があり、fsを使ったファイル操作とjsdomを使ったdom操作ができれば目的を達成できそう。ありがたいことに、既存HTMLはコピペで作られたようで、idやclassで目的の情報をピックアップできそうな雰囲気です。photoshopのバッチ処理みたいなことをjsでできれば言うことないなと。

Node.js | パス操作(path)とファイル操作(fs) - わくわくBank
pathモジュールを利用したパス操作方法、fsモジュールを利用したファイル操作方法(読み込み、書き込み、削除など)につい…
node.jsでファイルの読み込み、新規作成、上書き、追記、削除 | q-Az
node.jsのファイル操作の方法まとめです。ファイル操作に関する公式モジュールfsがあるのでそれを使って操作していきま…
初心者|node.jsでリネーム。フォルダからファイル名一覧を取得し一括変更する - Qiita
あるディレクトリの中にあるファイルたちの名前をまとめて変更したいなぁ、というときがあり、node.jsでやってみました。…

上記を参考に、手作業で元ファイルのフォルダ分けやテンプレートの作成などを行い、index.jsを書いて、node index.jsで発動!50個近いHTMLファイルが30秒もしないうちに作成されていきます。いくつかフォルダがあったので、それぞれに合わせて作業をしても、30分はかかりません。間違えても、修正して、node index.jsするだけ。すげぇな、node.js!とは言え、jsを書くのには結構時間がかかりましたが。腱鞘炎になることを思えば、全然いいですけどね。以下、いつも助けてくれるネットの方々へのお礼と感謝を込めてサンプルを掲載。粗が見えるjsですが、似たような課題に困っている誰かが救われると嬉しい限りです。nodeのバージョンとフォルダ構成は下記参照。

node version 16.13.2

//index.js srcフォルダ destフォルダがある

//元データのあるフォルダ、中に同じ内容のスマホ版とPC版のHTMLが2つづつある
/src/folder_name/a.html
/src/folder_name/sp_a.html
/src/folder_name/b.html
/src/folder_name/sp_b.html
/src/folder_name/…
//テンプレートのあるフォルダ 書き出し先も一緒 template.htmlはテンプレート
/dest/folder_name/template.html

//起動ファイル
index.js 

私の状況はスマホ版とPC版の別々に既存ファイルがあり、レスポンシブ化を行うための前段階として1つのファイルに一旦まとめるというもの。リンクのこともあるので、新しいファイルの名前はPC版と同じとします。事前にheader内情報や外部読み込みのファイルなどは記載しておき、PC版と同じ名前で元ファイルをコピーし、それぞれのファイルに対して、既存ファイルから情報を引っこ抜いてきて、追加し、保存することをファイルの数だけ繰り返します。以下編集の都合上3つに分けていますが、実際は1つのファイルindex.jsに記載されます。

const fs = require("fs");
const fsPromises = require("fs").promises;
const { JSDOM } = require("jsdom");
const srcDir = "./src/folder_name/";
const newDir = "./dest/folder_name/";
const templateFile = "./dest/template.html";

const fileNameList = fs.readdirSync(srcDir);
const targetFileNames = fileNameList.filter(RegExp.prototype.test, /.*\.html$/);

読み込みや設定部分。フォルダの中にある拡張子が.htmlだけを読み込みます。

async function action(pcFile, spFile, newFileName) {
  if (fs.existsSync(pcFile)) {
    try {
      const srcDataPc = await fsPromises.readFile(pcFile, "utf-8");
      const srcDataSp = await fsPromises.readFile(spFile, "utf-8");
      const domPc = new JSDOM(srcDataPc);
      const domSp = new JSDOM(srcDataSp);
      const wrapPc = domPc.window.document.querySelector("#main").innerHTML;
      const wrapSp = domSp.window.document.querySelector("#wrapper").innerHTML;
      try {
        const template = await fsPromises.readFile(newFileName, "utf-8");
        const dom = new JSDOM(template);
        const main = dom.window.document.querySelector(".main");
        let newDiv1 = dom.window.document.createElement("div");
        newDiv1.setAttribute("id", "main");
        newDiv1.setAttribute("class", "pc");
        main.appendChild(newDiv1);
        newDiv1.innerHTML = wrapPc;
        let newDiv2 = dom.window.document.createElement("div");
        newDiv2.setAttribute("id", "wrap");
        newDiv2.setAttribute("class", "sp");
        main.appendChild(newDiv2);
        newDiv2.innerHTML = wrapSp;
        const html = dom.window.document.querySelector("html").outerHTML;
        await fsPromises.writeFile(newFileName, html);
      } catch (err) {
        console.log(err);
      }
    } catch (err) {
      console.log(err);
    }
  }
}

既存ファイルから読み込み、新ファイルとして書き出します。実際実行するのはこの下にある部分です。途中、SPとPCのデータをそれぞれのidから読み込み、新たなdivを作って、そこに情報を入れ込みます。classやidを付与しているのは個人の都合なので、お好みで。

targetFileNames.forEach((targetFileName) => {
  if (targetFileName.includes("sp_")) {
    const anotherFileName = targetFileName.substring(3);
    const pcFile = srcDir + anotherFileName + ".html";
    const spFile = srcDir + targetFileName;
    const newFileName = newDir + anotherFileName  + ".html";

    fs.copyFile(templateFile, newFileName, (err) => {
      if (err) {
        console.log(err.stack);
      } else {
        console.log("Done.");
      }
    });
    action(pcFile, spFile, newFileName);
  }
});

フォルダにある既存ファイルすべてに対になるファイルがあるか確認し、あれば新しいフォルダにテンプレートをPC版と同じ名前で保存します。保存した後に、1個上のactionを実行し、情報をとって、追加し、保存する作業を行います。

コメント