• npm package
  • Github source repository

The installation

npm i juejin-save -g
Copy the code

use

juejin-save save https://xxx
Copy the code

The effect


1. Main Package version

Note: This article focuses on building the CLI, not puppeteer

package version function
commander ^ 9.0.0 Create processing command
inquirer ^ 8.2.0 Process interactions
ora ^ 5.4.1 Dealing with loading
puppeteer ^ 13.3.2 Control Chromium or Chrome via apis

2. Project directory structure

├ ─ ─ bin | └ ─ ─ cli. Js / / entry documents ├ ─ ─ LICENSE ├ ─ ─ package - lock. Json ├ ─ ─ package. The json ├ ─ ─ puppeteer. Js / / puppeteer save article file └ ─ ─ README.mdCopy the code

2. Add in package.jsonbinfield

Add the juejin-save command to specify the run file as the bin directory cli.js

+ {
+ "bin": {
+ "juejin-save": "bin/cli.js"
+}
+}
Copy the code

3. Main Package API introduction

3.1 commander

const { Command } = require("commander");
const program = new Command();

program
  .command("clone <source> [destination]")
  .description("clone a repository into a newly created directory")
  .action((source, destination) = > {
    console.log("clone command called");
  });

program.parse();
Copy the code

3.2 inquirer

var inquirer = require("inquirer");
inquirer
  .prompt([
    /* Pass your questions in here */
  ])
  .then((answers) = > {
    // Use user feedback for... whatever!!
  })
  .catch((error) = > {
    if (error.isTtyError) {
      // Prompt couldn't be rendered in the current environment
    } else {
      // Something else went wrong}});Copy the code

3.3 ora

import ora from "ora";

const spinner = ora("Loading unicorns").start();

setTimeout(() = > {
  spinner.color = "yellow";
  spinner.text = "Loading rainbows";
}, 1000);
Copy the code

3.4 puppeteer

const puppeteer = require("puppeteer");

(async() = > {const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto("https://example.com");
  await page.screenshot({ path: "example.png" });

  awaitbrowser.close(); }) ();Copy the code

4. Main logic code

  1. bin/cli.js
#! /usr/bin/env node

const inquirer = require("inquirer");
const ora = require("ora");
const { Command } = require("commander");
const { puppeteerInit, saveToHtml, saveToMd, saveToPdf } = require(path.resolve(
  __dirname,
  ".. /puppeteer"
));

const program = new Command();
const spinner = ora();

// Interactive query
async function handlePrompt() {
  return await inquirer.prompt([
    {
      name: "autoCreateFolder".message: `Automatically create folders? `.type: "confirm",},/ /...
  ]);
}

// Puppeteer initialization begins
async function AfterePrompt(articleUrl, answers) {
  spinner.color = "yellow";
  spinner.start("puppeteer intial...");

  const obj = await puppeteerInit(articleUrl, answers);

  spinner.stopAndPersist({
    symbol: chalk.green("✓"),
    text: chalk.green("puppeteer init ok")});return obj;
}

// Export the file
async function exportFile(arg) {
  const { page, outMdFilePath, outPdfFilePath, outHtmlfFilePath } = arg;
  await saveToMd(page, outMdFilePath);
  await saveToPdf(page, outPdfFilePath);
  await saveToHtml(page, outHtmlfFilePath);
}

// Step 1: create a command
program
  .version(require(path.resolve(__dirname, ".. /package.json")).version)
  .command("save 
      
       "
      )
  .description("save https://xxx")
  .action(async (articleUrl) => {
    // Step 2: Interactive query
    const answers = await handlePrompt(articleUrl);
    // Step 3: Get the interaction result
    const data = await AfterePrompt(articleUrl, answers);
    // Step 4: Export the file
    await exportFile(data);

    process.exit(1);
  });

program.parse();
Copy the code
  1. puppeteer.js
const puppeteer = require("puppeteer");

/ / save the HTML
async function saveToHtml(page, outHtmlfFilePath) {
  // ...
}

/ / save the markdown
async function saveToMd(page, outMdFilePath) {
  // ...
}

/ / save the PDF
async function saveToPdf(page, outPdfFilePath) {
  // ...
}

// Puppeteer is initialized
async function puppeteerInit(href) {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  page.setViewport({
    width: 1920.height: 1080});await page.goto(href, {
    waitUntil: "domcontentloaded".referer: href,
  });
  await page.waitForTimeout(3000); // Make sure the page loads

  return {
    browser,
    page,
  };
}

module.exports = {
  puppeteerInit,
  saveToHtml,
  saveToMd,
  saveToPdf,
};
Copy the code

5. Local tests

  1. Execute in the project root directory
npm link
Copy the code

After execution, success message:

added 1 package, and audited 3 packages in 1s

found 0 vulnerabilities
Copy the code

You can also find a soft link in the NPM global installation on your machine, as shown in the following figure:

  1. Open the cli in any directory and run
juejin-save save  https://juejin.cn/post/xxxx
Copy the code

Unsurprisingly, you can see that there is an extra folder where the article is saved.

6. Reference materials

  1. Hand-write a qualified front end scaffold

  2. CLI common tool kit – terminal interaction