- 作者:老汪软件技巧
- 发表时间:2024-09-03 11:01
- 浏览量:
前端开发已经越来越深入啦~ js也早就不仅仅是前端专属了。nodejs已经v20啦~
如果你开发过小程序、app。不知道有没有做过海报分享、导出pdf文件等需求。今天就用前端三件套(html + css + js)弄个导出pdf、图片功能吧,并提供 API 访问。以便在其他服务/终端中调用。
概览
本期两大主角:Puppeteer无头浏览器 + fastify快速且低开销的web框架
前者处理导出图片、pdf,后者提供API和静态资源访问。
为了方便服务器(Linux)上测试部署,这次还使用 docker 来构建部署服务。
文章涉及知识点有点多,虽然我写了保姆级注释。但是如果你不熟悉,那么请多翻阅文档。
1. Puppeteer
Puppeteer 是一个由 Google 开发的 Node.js 库,它提供了一组高级 API 来控制 Chrome 或 Chromium 浏览器。通过 Puppeteer,我们可以模拟用户在浏览器中的操作,如打开网页、点击按钮、填写表单等,还可以进行页面截图和生成 PDF 文件等操作。
puppeteer中文文档
2. Fastify
Fastify 是一个快速、低开销的 Node.js Web 框架,它以高性能和良好的扩展性而闻名。Fastify 提供了简洁的 API 和丰富的插件系统,可以方便地构建各种类型的 Web 服务。
OK、 主角介绍完了。你和主角能处到什么地步就靠各位自己了。
fastify中文文档
业务思考
经过了解后,puppeteer本质就是一个浏览器,所以肯定需要可以访问的 html页面、图片、文件资源来展示。以便后续操作。
需要可访问的html页面,可能你会想到nginx,但是别忘了主角Fastify不仅能提供API访问,还可以提供静态资源的访问。所以,先把web服务搞起来~
注意主角需要的 nodejs 版本哟~
搭建Fastify web服务
Fastify官网介绍呢,搭起来确实很快,但是呢,现在前端都是工程化时代啦、无论是 vue、还是 react 都是配的有 CLI 的。所以,Fastify肯定也是有的。
全局安装 fastify-cli
npm install --global fastify-cli
有求知欲的小伙伴可以输入看看 help
fastify --help
看看文档~
如上图,这里就不使用 TS 创建项目了,直接上 ESM
fastify generate myproject --esm
而后将得到如下工程:
有了package.json 前端的小伙伴就知道该怎么操作了吧?
# 安装依赖
npm i
# 启动~
npm run dev
启动成功~
而后就可以访问看看啦~
:3000/
添加Fastify插件
前面说到,我们要提供API、静态html资源访问。回想那段 CORS 跨域问题...
废话不多说,先看看 Fastify 生态:
就一个字:x
找到我们需要的:
然后安装...
npm i @fastify/cors @fastify/static
CLI工程已经有了对应plugin目录。这里就依葫芦画瓢,新建两个插件代码写写就好了。
注意这里创建了一个 public文件夹 用于存放静态资源。
这里ESM工程有个坑,nodejs内置的 __dirname 无法访问。这里改成这种就好:
import path from "path";
const __filename = new URL("", import.meta.url).pathname;
const __dirname = path.dirname(__filename);
至于插件更多配置,大家一定要去看文档啊~~
测试静态资源插件服务
在public文件夹下新增一个index.html文件
而后访问:
:3000/index.html
至此,已经完成了一大步~ 至少我们呈现的东西有了。现在需要去处理 puppeteer 啦。
叨扰puppeteer文档
如果非要说谁最熟悉puppeteer,那我估计就是puppeteer官方文档了。英文不要怕,实在不行就翻译呗~ 电脑又不会爆炸
假设~ 你已经看了看puppeteer文档↓↓↓
开干!
npm i puppeteer
编写fastify代码 导出pdfAPI:
import puppeteer from "puppeteer";
import path from "path";
const __filename = new URL("", import.meta.url).pathname;
const __dirname = path.join(__filename, "../../public");
export default async function (fastify, opts) {
fastify.get("/pdf", async function (request, reply) {
// 访问的地址
const host = `${request.protocol}://${request.hostname}`;
// 启动 puppeteer
const browser = await puppeteer.launch();
const page = await browser.newPage();
// 访问自己的 index.html 静态页面
await page.goto(`${host}/index.html`, {
waitUntil: "networkidle2",
});
// 导出 pdf
const pdfName = "test.pdf";
const pdfPath = path.join(__dirname, pdfName); // 导出文件路径
const opts = {
width: "60mm",
height: "80mm",
printBackground: true,
path: pdfPath,
};
// 网络可访问静态资源路径
const resourcePath = `${host}/${pdfName}`;
await page.pdf(opts);
await browser.close();
return { path: resourcePath };
});
}
以上代码很简单,基本来自puppeteer官方文档 pptr.dev/guides/pdf-…
效果如图:
编写fastify代码 导出图片API:
import puppeteer from "puppeteer";
import path from "path";
const __filename = new URL("", import.meta.url).pathname;
const __dirname = path.join(__filename, "../../public");
export default async function (fastify, opts) {
fastify.get("/img", async function (request, reply) {
// 访问的地址
const host = `${request.protocol}://${request.hostname}`;
// 启动 puppeteer
const browser = await puppeteer.launch();
const page = await browser.newPage();
// 访问自己的 index.html 静态页面
await page.goto(`${host}/index.html`, {
waitUntil: "networkidle2",
});
// 设置页面大小
await page.setViewport({ width: parseInt(60 * (96 / 25.4)), height: parseInt(80 * (96 / 25.4)) });
// 导出 图片
const imgName = "test.png";
const imgPath = path.join(__dirname, imgName); // 导出文件路径
const opts = {
path: imgPath,
};
// 网络可访问静态资源路径
const resourcePath = `${host}/${imgName}`;
await page.screenshot(opts);
await browser.close();
return { path: resourcePath };
});
}
其中setViewport设置页面大小的单位是px
效果如图:
至此 puppeteer 导出pdf、图片已完成。
大家一定要多看官方文档! 多检索官方文档~
部署又是一番折腾
开发环境始终和部署环境始终是有所不一样的。
在还没有部署之前,我就已经猜到了。正式 Linux 环境肯定又得折腾,而且还不好乱搞,不能影响其他正常服务。
所以这次也是搞了一波docekr。 大致几个问题:
国内环境网络是否能正常拉取镜像?如何编写构建镜像?如何构建运行?中文乱码问题
所以一些常见技术无论前端后端,都需要关注了解
首先在项目根目录 新建一个Dockerfile
这里我就不赘述了,大家直接看代码吧(我的保姆级注释):
# 使用官方Node.js基础镜像(这里用了镜像:国内网络环境问题...)
FROM hub.rat.dev/library/node:18-alpine3.19
# 设置工作目录
WORKDIR /app
# 复制package.json文件和package-lock.json文件(如果存在)
COPY package*.json .
# 安装项目依赖
RUN npm config set registry https://registry.npmmirror.com/
RUN npm install
# 阿里云镜像
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
# 安装必要的依赖
RUN apk add --no-cache \
chromium \
nss \
freetype \
harfbuzz \
ca-certificates \
ttf-freefont \
nodejs \
yarn \
# 中文字体乱码问题
ttf-dejavu \
font-droid-nonlatin \
msttcorefonts-installer fontconfig && \
update-ms-fonts && \
fc-cache -f
# 安装puppeteer依赖
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
# 设置时区为上海
ENV TZ=Asia/Shanghai
# 设置语言为中文
ENV LANG=zh_CN.UTF-8
# 安装 puppeteer
RUN yarn add puppeteer@13.5.0
# 复制项目文件到工作目录
COPY . .
# 暴露容器端口
EXPOSE 3000
# 运行Node.js应用
CMD ["npm", "run", "start"]
1. 网络环境问题:
设置镜像地址,然后重启docker
sudo tee /etc/docker/daemon.json <<EOF
{
"registry-mirrors": [
"https://docker.anyhub.us.kg",
"https://dockerhub.jobcher.com",
"https://dockerhub.icu",
]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
2. 构建镜像
docker build -t node-puppeteer .
3. 构建运行
docker run -d --name node-puppeteer -p 3000:3000 node-puppeteer:latest
4. 中文乱码问题
最开始构建的时候遇到了,最后才修改成了上面的Dockerfile:
解决方式就是 安装字体
见上方 Dockerfile
docker不熟悉的童鞋,可以去看看官方文档或者其他文章。
总结
通过结合使用 Puppeteer 和 Fastify,我们可以轻松地在前端实现 PDF,图片导出功能。Puppeteer 提供了强大的浏览器控制能力,而 Fastify 则提供了高效的 Web 服务框架,两者结合起来可以满足各种复杂的业务需求。
在实际应用中,我们可以根据具体需求调整页面导航、PDF,图片生成选项等参数。
总之,Puppeteer 和 Fastify 为前端开发人员提供了一种强大的工具组合,可以帮助我们实现各种有趣和实用的功能。
如果过程中遇到什么问题,欢迎各位评论说私信交流~
点个赞吧~ 手机不会掉地上、电脑也不会爆炸