前端导出pdf、图片很难吗?js一把梭~前端导出pdf、图片很难吗?js一把梭~ 前端开发已经越来越深入啦~ js也早就
前端开发已经越来越深入啦~ 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 文件
等操作。
2. Fastify
Fastify
是一个快速、低开销
的 Node.js Web 框架
,它以高性能
和良好的扩展性
而闻名。Fastify 提供了简洁的 API 和丰富的插件系统,可以方便地构建各种类型的 Web 服务。
OK、 主角介绍完了。你和主角能处到什么地步就靠各位自己了。
业务思考🤔
经过了解后,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
启动成功~
而后就可以访问看看啦~
http://127.0.0.1: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
文件
而后访问:
http://127.0.0.1:3000/index.html
至此,已经完成了一大步~ 至少我们呈现的东西有了。现在需要去处理 puppeteer 啦。
叨扰puppeteer文档
如果非要说谁最熟悉puppeteer
,那我估计就是puppeteer官方文档
了。英文不要怕,实在不行就翻译呗~ 电脑又不会爆炸💥
假设~ 你已经看了看puppeteer文档↓↓↓
开干!
npm i puppeteer
编写fastify
代码 导出pdf
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("/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 .
-t node-puppeteer
:指定构建
的镜像名称
为 “node-puppeteer”。这里的 “node-puppeteer” 可以是任何你想要的名称,它将用于标识这个特定的镜像。.
:表示Dockerfile 所在的当前目录
。Docker
会在这个目录中查找
名为“Dockerfile”
的文件,并根据其中的指令来构建镜像
。
3. 构建运行
docker run -d --name node-puppeteer -p 3000:3000 node-puppeteer:latest
-
-d
:表示以分离模式
(detached mode)运行容器,即在后台运行容器
,不会将容器的输出直接打印到终端。 -
--name node-puppeteer
:为容器指定一个名称为 “node-puppeteer”。这样可以方便地通过名称来管理和引用这个容器。 -
-p 3000:3000
:进行端口映射。将容器内部
的3000 端口
映射到主机
的3000 端口
。这意味着可以通过访问主机的 3000 端口来访问容器内运行在 3000 端口的服务。 -
node-puppeteer:latest
:指定要运行
的Docker
镜像名称和标签
。这里表示使用名为 “node-puppeteer” 且标签为 “latest” 的镜像来创建容器。
4. 中文乱码问题
最开始构建的时候遇到了,最后才修改成了上面的Dockerfile
:
解决方式就是 安装字体
😄
见上方 Dockerfile
docker
不熟悉的童鞋,可以去看看官方文档或者其他文章。
总结
通过结合使用 Puppeteer
和 Fastify
,我们可以轻松地在前端
实现 PDF,图片导出
功能。Puppeteer
提供了强大的浏览器控制能力
,而 Fastify
则提供了高效的 Web 服务框架
,两者结合起来可以满足各种复杂的业务需求
。
在实际应用中
,我们可以根据具体需求
调整页面导航、PDF,图片生成选项
等参数
。
总之,Puppeteer
和 Fastify
为前端开发人员
提供了一种强大的工具组合
,可以帮助我们实现各种有趣
和实用的功能
。
如果过程中遇到什么问题,欢迎各位评论说私信交流~
点个赞吧~ 手机不会掉地上、电脑也不会爆炸💥
转载自:https://juejin.cn/post/7409828788127268873