会将整个页面获取到的数据全部储存起来,在一个id="NUXT_DATA"的 script 标签里。查阅官方文档,github讨论区,发现众多网友都有此问题,但官方大大并不认为这有问题。
这就需要你页面的数据全部脱敏才行,不然真的明目张胆的将数据完全暴露出去。
问题无解,暂未找到很合理的办法。
第一次尝试
使用render:html钩子在加载页面前提取__NUXT_DATA__数据放到一个新的 js 文件存到_nuxt下, 再插入新的 script 来外部引用,能够减少页面大小
// 文件目录 /mixin/nitro-hooks.ts
// 使用 nitro-hooks
import fs from 'fs';
import path from 'path';
export default defineNitroPlugin((nitro) => {
nitro.hooks.hook("render:html",async (html, events) => {
const data = html.bodyAppend[0];
const regex = /<script type="application\/json" id="__NUXT_DATA__" data-ssr="true">([^<]*)<\/script>/;
// 要写入的内容
const content = data.match(regex)[1];
// =========
const routePath: any = events.event.context.matchedRoute
// scriptSrc
const buildAssetsDir = events.event.context.nitro.runtimeConfig.app.buildAssetsDir;
// 例如,向打包后的文件写入一个文件
// 确保目标文件的目录存在,如果不存在则创建
const distDir = '/_nuxt/'
if (!fs.existsSync(distDir)) {
fs.mkdirSync(distDir, { recursive: true })
}
const fileName = `state-${routePath.params._ || "home" }.js`
// 构建完整的文件路径
const filePath = path.join(distDir, buildAssetsDir, fileName);
// 使用 fs 模块向文件中写入内容
try {
const scriptSrc = path.join(buildAssetsDir, fileName);
await fs.promises.appendFile(filePath, content);
html.bodyAppend[0] = data.replace(regex, `<script defer src="${scriptSrc}"></script>`);
console.log('Custom content has been written to the file:', filePath)
} catch (error) {
console.error('Error writing content to file:', error)
}
});
})
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
compressPublicAssets: true,
plugins: [
'~/mixin/nitro-hooks.ts',
]
},
})
结果:并没有什么卵用,这个方法在用户每次请求都会生成一个文件,不合理。(错误实例
第二次尝试
对一次尝试进行优化,思路: 预先生成版本号(时间戳 大于 当前时间),每次生成文件时,判断是否有该版本号的文件,
有: 直接读取
无: 生成文件
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook("render:html",async (html, { event }) => {
// 当前路由 => 首页
const route = event._path.replaceAll("/", "__");
// 版本号
const version = (new Date("2024-06-30").getTime()).toString();
// 匹配到需要提取的 __NUXT_DATA
const nuxtData = getNuxtDataContent(html.bodyAppend[0]);
// 获取当前工作目录
const currentDirectory = process.cwd();
const _nuxtDirectory = path.join(currentDirectory, 'public', '_nuxt');
// 版本文件夹
const versionDirectory = path.join(_nuxtDirectory, `state-${route}-${version}.js`);
console.log(`版本文件: ${versionDirectory}`);
// 是否存在
if (!fs.existsSync(versionDirectory)) {
try {
console.log("不存在 => 创建");
// 不存在 => 创建
await fs.mkdirSync(_nuxtDirectory, { recursive: true });0
await fs.promises.writeFile(versionDirectory, nuxtData, 'utf-8');
html.bodyAppend[0] = replaceContent(html.bodyAppend[0], version, route);
console.log('Custom content has been written to the file:', versionDirectory);
} catch (error) {
console.error('Error writing content to file:', error)
}
} else {
console.log("存在 => 直接替换");
// 存在 => 直接替换
html.bodyAppend[0] = replaceContent(html.bodyAppend[0], version, route);
}
})
})
// 提取 __NUXT_DATA__ value
function getNuxtDataContent (data) {
const regex = /<script>([^<]*)<\/script>/;
const content = data.match(regex)[1];
return content;
}
// 字符替换 返回值
function replaceContent (data, version, route) {
// const regex = /<script type="application\/json" id="__NUXT_DATA__" data-ssr="true">([^<]*)<\/script>/;
// const content = data.replace(regex, `<script type="application\/json" id="__NUXT_DATA__" data-ssr="true" defer src="/_nuxt/state-${route}-${version}.js"></script>`);
// return content;
return `<script defer src="/_nuxt/state-${route}-${version}.js"></script>`;
}
需要注意的是,需要把 nuxt.config.ts 改个配置
export default defineNuxtConfig({
// .......
experimental: {
// 不把数据生成一个单独的 JSON
renderJsonPayloads: false
},
})
结果
这里文件已经写入,也成功引用了,但是却有了副作用,控制台报错
写入的文件并没有识别到。
待解决:
1、需要一个静态资源文件夹,将写入的内容写到静态文件夹
2、版本号的时间戳小于当前时间戳,需重新刷新版本号