From 9ed5b3fe790a63c2eb125b3fd9274d55bcbc5d4c Mon Sep 17 00:00:00 2001 From: Loren Date: Tue, 24 Nov 2020 16:13:48 -0500 Subject: [PATCH] Add the ability to keep individual files and filter files --- README.md | 61 +++++++++++++++++++++++++++++++++++++-- src/extendCli.js | 12 +++++--- src/generatePdf.js | 72 +++++++++++++++++++++++++++++----------------- 3 files changed, 112 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index adffaba..1b6c113 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,32 @@ Vuepress plugin for exporting site as PDF - Designed to work well in headless environments like CI runners ## Config options +- `filter` - function for filtering pages (default `false`) +- `individualPdfFolder` - string (default temp dir), if supplied will save the individual PDFs and a `files.json` file + with the title, url, location, path, key, and frontmatter for each PDF to allow later combining/mapping - `theme` - theme name (default `@vuepress/default`) -- `sorter` - function for changing pages order (default `false`) -- `outputFileName` - name of output file (default `site.pdf`) +- `outputFileName` - name of output file (default `site.pdf`, or null to skip creating a combined file (useful if saving individual PDFs)) - `puppeteerLaunchOptions` - [Puppeteer launch options object](https://github.com/puppeteer/puppeteer/blob/v2.1.1/docs/api.md#puppeteerlaunchoptions) (default `{}`) - `pageOptions` - [Puppeteer page formatting options object](https://github.com/puppeteer/puppeteer/blob/v2.1.1/docs/api.md#pagepdfoptions) (default `{format: 'A4'}`) +- `sorter` - function for changing pages order (default `false`) + +### Sort/Filter Functions + +The input to each is page object(s) from Vuepress context: +[https://vuepress.vuejs.org/plugin/context-api.html#ctx-pages](https://vuepress.vuejs.org/plugin/context-api.html#ctx-pages) + +There is better documenation about the properties of a page object currently available at: +[https://vuepress.vuejs.org/plugin/option-api.html#extendpagedata](https://vuepress.vuejs.org/plugin/option-api.html#extendpagedata) + +At the time of writing all the keys available were: +`title`, `_meta`, `_filePath`, `_content`, `_permalink`, `frontmatter`, `_permalinkPattern`, `_extractHeaders`, +`_context`, `regularPath`, `relativePath`, `key`, `path`, `_strippedContent`, `headers`, `_computed`, `_localePath` + +Sort will receive `(a, b)` where `a` and `b` are page objects and should return an integer. -### Usage +Filter will receive a page object and the index and should return `true`/`false`. + +## Usage Using this plugin: @@ -25,6 +44,42 @@ module.exports = { } ``` +Using the plugin with options: + +```js +// in .vuepress/config.js +module.exports = { + // ... + plugins: [ + // ... + [ + require("../../vuepress-plugin-pdf-export"), + { + // options to override + outputFileName: null, + pageOptions: { + format: 'Letter', + printBackground: true, + displayHeaderFooter: false, + headerTemplate: "", + footerTemplate: "", + margin: { + top: "1in", + left: "1in", + right: "1in", + bottom: "1in", + } + }, + individualPdfFolder: 'build/pdf', + filter: (a) => !a?.frontmatter?.home, + sorter: (a, b) => a.path < b.path ? -1 : 1, + } + ] + ], + // ... +}; +``` + Then run: ``` bash diff --git a/src/extendCli.js b/src/extendCli.js index bd09f70..3d90210 100644 --- a/src/extendCli.js +++ b/src/extendCli.js @@ -7,10 +7,12 @@ const generatePDF = require('./generatePdf') module.exports = options => { const theme = options.theme || '@vuepress/default' + const filter = options.filter || false const sorter = options.sorter || false - const outputFileName = options.outputFileName || 'site.pdf' + const outputFileName = options.outputFileName === null ? null : options.outputFileName || 'site.pdf' const puppeteerLaunchOptions = options.puppeteerLaunchOptions || {} const pageOptions = options.pageOptions || {} + const individualPdfFolder = options.individualPdfFolder; return cli => { cli @@ -30,12 +32,14 @@ module.exports = options => { try { await generatePDF(nCtx, { - port: nCtx.devProcess.port, + filter, host: nCtx.devProcess.host, - sorter, + individualPdfFolder, outputFileName, + pageOptions, + port: nCtx.devProcess.port, puppeteerLaunchOptions, - pageOptions + sorter, }) } catch (error) { console.error(red(error)) diff --git a/src/generatePdf.js b/src/generatePdf.js index 1c0514a..4cc98a9 100644 --- a/src/generatePdf.js +++ b/src/generatePdf.js @@ -5,16 +5,22 @@ const { fs, logger, chalk } = require('@vuepress/shared-utils') const { yellow, gray } = chalk module.exports = async (ctx, { - port, + filter, host, - sorter, + individualPdfFolder, outputFileName, + pageOptions, + port, puppeteerLaunchOptions, - pageOptions + sorter, }) => { const { pages, tempPath } = ctx - const tempDir = join(tempPath, 'pdf') - fs.ensureDirSync(tempDir) + const pdfDir = individualPdfFolder || join(tempPath, 'pdf') + + if (individualPdfFolder && fs.existsSync(pdfDir)) { + fs.removeSync(pdfDir) + } + fs.ensureDirSync(pdfDir) let exportPages = pages.slice(0) @@ -22,12 +28,18 @@ module.exports = async (ctx, { exportPages = exportPages.sort(sorter) } + if (typeof filter === 'function') { + exportPages = exportPages.filter(filter) + } + exportPages = exportPages.map(page => { return { url: page.path, title: page.title, location: `http://${host}:${port}${page.path}`, - path: `${tempDir}/${page.key}.pdf` + path: `${pdfDir}/${page.key}.pdf`, + key: page.key, + frontmatter: page.frontmatter, } }) @@ -50,35 +62,43 @@ module.exports = async (ctx, { ) await browserPage.pdf({ - path: pagePath, format: 'A4', - ...pageOptions + ...pageOptions, + path: pagePath, }) logger.success(`Generated ${yellow(title)} ${gray(`${url}`)}`) } - await new Promise(resolve => { - const mergedPdf = new pdf.Document() + if (individualPdfFolder) { + fs.writeFileSync(`${pdfDir}/files.json`, JSON.stringify(exportPages), {encoding: 'UTF8'}) + } + + if (outputFileName) { + await new Promise(resolve => { + const mergedPdf = new pdf.Document() - exportPages - .map(({ path }) => fs.readFileSync(path)) - .forEach(file => { - const page = new pdf.ExternalDocument(file) - mergedPdf.addPagesOf(page) - }) + exportPages + .map(({path}) => fs.readFileSync(path)) + .forEach(file => { + const page = new pdf.ExternalDocument(file) + mergedPdf.addPagesOf(page) + }) - mergedPdf.asBuffer((err, data) => { - if (err) { - throw err - } else { - fs.writeFileSync(outputFileName, data, { encoding: 'binary' }) - logger.success(`Export ${yellow(outputFileName)} file!`) - resolve() - } + mergedPdf.asBuffer((err, data) => { + if (err) { + throw err + } else { + fs.writeFileSync(outputFileName, data, {encoding: 'binary'}) + logger.success(`Export ${yellow(outputFileName)} file!`) + resolve() + } + }) }) - }) + } await browser.close() - fs.removeSync(tempDir) + if (!individualPdfFolder) { + fs.removeSync(pdfDir) + } }