1.前言
这两天朋友在群里问了这个问题,尝试过网上的方法,发现都没作用,于是研究花点时间研究了一会,终于把问题解决
项目环境
nuxt:3.0.0
node:16.15.0
vue:3.2.47
vite:3.2.5
2.说说网上的方案
vue-renderer:ssr:context
// Call ssr:context hook
await this.serverContext.nuxt.callHook('vue-renderer:ssr:context', renderContext)
以上代码是在nuxt 2.x源码,vue-renderer:ssr:context被触发时,返回一个渲染的上下文对象,通过此对象可以进行处理window._NUXT_
这也是在网上搜索得出的答案大部分指向这个,实际上在nuxt3此hooks已被删除,如果是nuxt 2.x版本可以利用此hooks去掉window._NUXT_,在此就不再列出具体示例代码
3.说说nuxt3的hooks
nuxt3提供了三类hooks分别是
App Hooks (runtime)(应用运行时hooks)
| hook名称 | 参数 | 环境 | 描述 |
|---|---|---|---|
app:created | vueApp | 服务器和客户端 | 创建初始实例时调用。vueApp |
app:error | err | 服务器和客户端 | 发生致命错误时调用。 |
app:error:cleared | { redirect? } | 服务器和客户端 | 发生致命错误时调用。 |
app:data:refresh | keys? | 服务器和客户端 | (内部) |
vue:setup | - | 服务器和客户端 | (内部) |
vue:error | err, target, info | 服务器和客户端 | 当 vue 错误指向根组件时调用。了解更多信息. |
app:rendered | renderContext | 服务器 | SSR 渲染完成后调用。 |
app:redirected | - | 服务器 | 在 SSR 重定向之前调用。 |
app:beforeMount | vueApp | 客户 | 在挂载应用之前调用,仅在客户端调用。 |
app:mounted | vueApp | 客户 | 在浏览器中初始化并挂载 Vue 应用时调用。 |
app:suspense:resolve | appComponent | 客户 | 挂载完成 调用 |
link:prefetch | to | 客户 | 当观察到 被预取时调用。<NuxtLink> |
page:start | pageComponent? | 客户 | 调用挂起的事件。 |
page:finish | pageComponent? | 客户 | 调用加载完成的事件。 |
page:transition:finish | pageComponent? | 客户 | 页面过渡后事件。 |
Nuxt Hooks (build time)(构建时hooks)
| hook名称 | 参数 | 描述 |
|---|---|---|
kit:compatibility | compatibility, issues | 允许扩展兼容性检查。 |
ready | nuxt | 在Nuxt初始化后调用,当Nuxt实例准备好工作时。 |
close | nuxt | 在 Nuxt 实例正常关闭时调用。 |
modules:before | - | 在Nuxt初始化期间,在安装用户模块之前调用。 |
modules:done | - | 在Nuxt初始化期间,安装用户模块后调用。 |
app:resolve | app | 解析实例后调用。app |
app:templates | app | 在生成过程中调用,以允许自定义、修改或将新文件添加到构建目录(虚拟或写入)。NuxtApp``.nuxt |
app:templatesGenerated | app | 在模板编译到虚拟文件系统(VFS)。 |
build:before | - | 在Nuxt捆绑构建器之前调用。 |
build:done | - | 在Nuxt捆绑包生成器完成后调用。 |
build:manifest | manifest | 在清单构建期间由 Vite 和 Webpack 调用。这允许自定义 Nitro 将用于在最终 HTML 中呈现和标记的清单。<script>``<link> |
builder:generateApp | options | 在生成应用之前调用。 |
builder:watch | event, path | 在开发中的生成时,当观察程序发现对项目中的文件或目录的更改时调用。 |
pages:extend | pages | 解析页面路由后调用。 |
server:devHandler | handler | 在 Nitro 开发服务器上注册开发中间件时调用。 |
imports:sources | presets | 在设置时调用,允许模块扩展源。 |
imports:extend | imports | 在安装程序时调用,允许模块扩展导入。 |
imports:context | context | 调用时取消导入创建上下文。 |
imports:dirs | dirs | 允许扩展导入目录。 |
components:dirs | dirs | 在允许内调用,以扩展扫描的目录以查找可自动导入的组件。app:resolve |
components:extend | components | 允许扩展新组件。 |
nitro:config | nitroConfig | 在初始化 Nitro 之前调用,允许自定义 Nitro 的配置。 |
nitro:init | nitro | 在 Nitro 初始化后调用,这允许注册 Nitro 钩子并直接与 Nitro 交互。 |
nitro:build:before | nitro | 在构建 Nitro 实例之前调用。 |
prerender:routes | ctx | 允许扩展要预渲染的路由。 |
build:error | error | 在生成时发生错误时调用。 |
prepare:types | options | 在 Nuxi 编写 和 之前调用,允许在 中添加自定义引用和声明,或直接修改 中的选项.nuxt/tsconfig.json``.nuxt/nuxt.d.ts``nuxt.d.ts``tsconfig.json |
listen | listenerServer, listener | 在加载开发服务器时调用。 |
schema:extend | schemas | 允许扩展默认架构。 |
schema:resolved | schema | 允许扩展解析的架构。 |
schema:beforeWrite | schema | 在编写给定架构之前调用。 |
schema:written | - | 在写入架构后调用。 |
vite:extend | viteBuildContext | 允许扩展 Vite 默认上下文。 |
vite:extendConfig | viteInlineConfig, env | 允许扩展 Vite 默认配置。 |
vite:serverCreated | viteServer, env | 创建 Vite 服务器时调用。 |
vite:compiled | - | 在编译 Vite 服务器后调用。 |
webpack:config | webpackConfigs | 在配置 webpack 编译器之前调用。 |
webpack:compile | options | 在编译之前调用。 |
webpack:compiled | options | 加载资源后调用。 |
webpack:change | shortPath | 在Webpack上调用。change |
webpack:error | - | 如果 Webpack 上有错误,则调用。done |
webpack:done | - | 在Webpack上调用。allDone |
webpack:progress | statesArray | 在Webpack上调用。progress |
Nitro App Hooks (runtime, server-side)(Nitro运行时,服务端)
| 钩 | 参数 | 描述 | 类型 |
|---|---|---|---|
render:response | response, { event } | 在发送响应之前调用。 | 响应,事件 |
render:html | html, { event } | 在构造 HTML 之前调用。 | .html,事件 |
3.解决方案
本次nuxt3借助Nitro App Hooks的render:html拿到预渲染的htmlContext,进一步处理达到完整去掉window.__NUXT__
最佳实践
在项目根目录创建server文件夹,在server文件夹下创建plugins文件夹,在plugins文件下创建nitroPlugin.ts
export default defineNitroPlugin((nitroApp: { hooks: { hook: (arg0: string, arg1: (html: { bodyAppend: string[] }, { event }: any) => void) => void } }) => {
nitroApp.hooks.hook('render:html', (html: { bodyAppend: string[] }, { event }: any) => {
let index = html.bodyAppend.findIndex(i => i.indexOf('window.__NUXT__') != -1 )
if(index != -1){
html.bodyAppend.splice(index,1)
}
})
})
render:html会返回什么
通过render:html拿到的是什么数据结构,通过源码发现
返回了htmlContext(详细看下图),此htmlContext包含了整个首页的渲染数据,以及各种css,js的引用,window.__NUXT__ 就在bodyAppend字段中,bodyAppend会存在多个script,通过上述代码进行遍历查找bodyAppend确定window.__NUXT__ 的位置,进而进行删除