- 1. 概要
- 2. 状況
- 3. server.js
- 4. 呼び出し側
- 5. 参考サイト
1. 概要
説明が、なかなか難しい。
2. 状況
もともと、あるコンテンツを「HTML」表示したものをバックで、「.pdf」化するというのが命題なのですが。
そのコンテンツが、中で、「Vue.js」を動作させているのです。
前ページの状態だと、コンテンツ表示の際の、「Vue.js」が動作しないので、「.pdf」化したものは、真っ白のものができあがります。
コンテンツ内の「Vue.js」まで動作させるには、もうひと工夫必要です。
3. server.js
「server.js」の記述は、こうなります。
const express = require('express');
const bodyParser = require('body-parser');
const puppeteer = require('puppeteer');
const app = express();
app.use(bodyParser.json({ limit: '50mb' }));
app.post('/generate-pdf', async (req, res) =>
{
const url = req.body.url;
if (!url) return res.status(400).send('URL is required');
process.env.HOME = '/path';
process.env.XDG_CONFIG_HOME = '/path/.config';
process.env.XDG_DATA_HOME = '/path/.local/share';
let browser;
try {
browser = await puppeteer.launch({
headless: 'new',
executablePath: '/usr/bin/chromium-browser',
args: ['--no-sandbox', '--disable-setuid-sandbox'],
userDataDir: '/path/.chromium', // apache が書き込み可能な場所
});
const page = await browser.newPage();
await page.goto(url, {
waitUntil: 'networkidle0', // Vue や Ajax が落ち着くまで待つ
timeout: 60000
});
const pdfBuffer = await page.pdf({
format: 'A4',
landscape: true,
printBackground: true,
margin: {
top: '20mm',
bottom: '20mm',
left: '15mm',
right: '15mm'
}
});
await browser.close();
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', 'attachment; filename="document.pdf"');
res.send(pdfBuffer);
} catch (error) {
if (browser) await browser.close();
console.error(error);
res.status(500).send('PDF generation failed');
}
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Puppeteer server running on port ${PORT}`);
});
前ページは、入力引数の「req」の「req.body.html」コンテンツのみ引っ張り出して、ブラウザに表示させていますが。
本ページの場合、入力引数は、コンテンツのリクエスト自体をブラウザで展開させています。
展開するので、ワークディレクトリが必要になるので、13~15行目や、23行目で、ディレクトリを定義しています。
さらに、「JavaScript」や「Vue.js」が動作する時間を 28~30行目で待って、落ち着いてから、「.pdf」化しているわけです。
4. 呼び出し側
呼び出し側も前ページでは。
$html = view('any_page')->render();
// Node.js Puppeteer サーバーに送信
$response = Http::post('http://127.0.0.1:3000/generate-pdf', [
'html' => $html
]);
と、「html」部分を渡していましたが・・・。
本ページの方式の場合、だいぶ複雑になります。
「Laravel」でやるときは、まず、「node server.js」内で表示させるコンテンツのルートを定義します。
routes/web.php
内に下記のようなルートを定義します。
Route::get('/hogehoge_root', [ HogehogeController::class, 'viewHogehoge' ])->name('piyopiyo');
呼び出し側で、「server.js」アクセス時に。
$params =
[
'param1' => $param1,
'param2' => $param2,
];
$url = route('piyopiyo', $params);
$response = Http::post('http://127.0.0.1:3000/generate-pdf', [ 'url' => $url, ]);
てなコードを書きます。
ここ「$url = route(...)」と、「$response = Http::post(...)」の行は、わけて記述しないと。
呼び出し先に、うまくパラメータがわたりません。
呼び出し先の。下記のファイル内に。
app/Http/Controllers/Api/HogehogeController.php
下記のようなコードを記述します。
public function viewHogehoge(Request $request)
{
try
{
$params = (object)$request->all();
$param1 = $params->param1;
$param2 = $params->param2;
return view('view_blade', compact(
'param1',
'param2',
));
}
catch (Exception $ex)
{
logger($ex->getMessage());
throw $ex;
}
}
これで、「server.js」の先で、「javascript」「Vue.js」が動作した後、「.pdf」化することになります。
5. 参考サイト
本ページは、「ChatGPT」くんを参考にさせていただきました。
|