bridge icon indicating copy to clipboard operation
bridge copied to clipboard

Nuxt Bridge 非 SSR 下编译异常及解决建议

Open woodcoal opened this issue 3 years ago • 1 comments

Nuxt Bridgessr:falsetarget:static 下无法编译调试的故障,初步测试从 3.0.0-27437402.494f85a 到 3.0 RC1 都有问题。 我的开发环境是:

  • windows 10 / 11
  • nodejs v16.14.2
  • Nuxt CLI v3.0.0-rc.1-27517945.7e912e7
  • Webpack

问题 1: nuxt.config.js 中 ssr:false 时,出现无法找到 /.nuxt/dist/server/server.mjs 文件错误

ERROR Rollup error: Could not load file:///D:/***/.nuxt/dist/server/server.mjs (imported by node_modules/@nuxt/bridge/dist/runtime/nitro/renderer.mjs): ENOENT: no such file or directory, open 'D:\***\.nuxt\dist\server\server.mjs'

分析 node_modules/@nuxt/bridge/dist/runtime/nitro/renderer.mjs 发现,位于 11 行 const getSSRApp = !process.env.NUXT_NO_SSR && cachedImport(() => import("#build/dist/server/server.mjs")); 非 ssr 状态下不引用 #build/dist/server/server.mjs

按 nuxt 的思路,非 ssr 模式下,不会在 .nuxt/dist/server 下生成服务端相关文件,但是系统编译时不管是不是 ssr 模式,Webpack 都会尝试 import 这个文件,一旦没发现这个文件就报错。

所以目前想到的办法就是,不管是不是 ssr 都在 server 下生成 server.mjs

找到 node_modules/@nuxt/bridge/dist/chunks/module.mjs 约 209-306 行

if (name === "server") {
  const jsServerEntry = resolve(nuxt.options.buildDir, "dist/server/server.js");
  await promises.writeFile(jsServerEntry.replace(/.js$/, ".cjs"), 'module.exports = require("./server.js")', "utf8");
  await promises.writeFile(jsServerEntry.replace(/.js$/, ".mjs"), 'export { default } from "./server.cjs"', "utf8");
} else if (name === "client") {
  const manifest = await promises.readFile(resolve(nuxt.options.buildDir, "dist/server/client.manifest.json"), "utf8");
  await promises.writeFile(resolve(nuxt.options.buildDir, "dist/server/client.manifest.mjs"), "export default " + manifest, "utf8");
}

大致意思是服务端调用时生成服务端文件,可以端调用是生成客户端文件,调试发现,当 ssr:true 时会分别走一次 server 和 client,但是 ssr:false 时,server 就不会调用,这样 .nuxt/dist/server 下没有 server.mjs 自然就出错。

解决办法: 临时解决办法就是 client 调用检测到为 非 ssr 模式时,同时生成 server.mjs 空文件,即:

if (name === "server") {
  const jsServerEntry = resolve(nuxt.options.buildDir, "dist/server/server.js");
  await promises.writeFile(jsServerEntry.replace(/.js$/, ".cjs"), 'module.exports = require("./server.js")', "utf8");
  await promises.writeFile(jsServerEntry.replace(/.js$/, ".mjs"), 'export { default } from "./server.cjs"', "utf8");
} else if (name === "client") {
  if (nuxt.options.ssr === false){
    const jsServerEntry = resolve(nuxt.options.buildDir, "dist/server/server.js");
    await promises.writeFile(jsServerEntry.replace(/.js$/, ".mjs"), 'export default {}', "utf8");
  }
  const manifest = await promises.readFile(resolve(nuxt.options.buildDir, "dist/server/client.manifest.json"), "utf8");
  await promises.writeFile(resolve(nuxt.options.buildDir, "dist/server/client.manifest.mjs"), "export default " + manifest, "utf8");
}

问题 2: target:static 时执行 nuxi generate 错误

FATAL  [nitro] Please use nuxt generate for static target                                                    10:10:20

  at setupNitroBridge (/D:/***/node_modules/@nuxt/bridge/dist/chunks/module.mjs:150:11)
  at /D:/***/node_modules/@nuxt/bridge/dist/chunks/module.mjs:1300:15
  at node_modules\hable\dist\hable.js:1:990
  at node_modules\hable\dist\hable.js:1:208
  at async Nuxt.callHook (node_modules\hable\dist\hable.js:1:959)
  at async ModuleContainer.ready (node_modules\@nuxt\core-edge\dist\core.js:49:5)
  at async Nuxt._init (node_modules\@nuxt\core-edge\dist\core.js:346:5)

解决办法: 警告信息明确提示使用 nuxt generate 而不是 nuxi ,但是不知为何官方文档标注是使用 nuxi

问题 3: target:static 时执行 nuxt generate 编译失败, ESM 无法加载

 FATAL  Only file and data URLs are supported by the default ESM loader. On Windows, absolute paths must be valid file:// URLs. Received protocol 'd:'

  at new NodeError (node:internal/errors:371:5)
  at throwIfUnsupportedURLProtocol (node:internal/modules/esm/resolve:1035:11)
  at defaultResolve (node:internal/modules/esm/resolve:1105:3)
  at ESMLoader.resolve (node:internal/modules/esm/loader:530:30)
  at ESMLoader.getModuleJob (node:internal/modules/esm/loader:251:18)
  at ESMLoader.import (node:internal/modules/esm/loader:332:22)
  at importModuleDynamically (node:internal/modules/esm/translators:106:35)
  at importModuleDynamicallyCallback (node:internal/process/esm_loader:35:14)
  at prerender (/D:/***/node_modules/nitropack/dist/chunks/prerender.mjs:2169:39)
  at async /D:/***/node_modules/@nuxt/bridge/dist/chunks/module.mjs:348:9
  at async Nuxt.callHook (node_modules\hable\dist\hable.js:1:959)
  at async Builder.build (node_modules\@nuxt\builder-edge\dist\builder.js:264:5)
  at async ensureBuild (node_modules\@nuxt\cli-edge\dist\cli-generate.js:126:3)
  at async Object.run (node_modules\@nuxt\cli-edge\dist\cli-generate.js:243:7)
  at async NuxtCommand.run (node_modules\@nuxt\cli-edge\dist\cli-index.js:370:7)

这个问题的原因时编译后调用模块使用了绝对地址,如:d:\ ……\xxx.js,而这种地址是无法正常加载的,需要使用 file:// 头,即:file://d:\ …… \xxx.js

解决办法: 打开 /node_modules/nitropack/dist/chunks/prerender.mjs 第 2169 行 找到:const { localFetch } = await import(resolve(nitroRenderer.options.output.serverDir, "index.mjs")); 改为:const { localFetch } = await import('file://' + resolve(nitroRenderer.options.output.serverDir, "index.mjs"));

问题 4:target:static 时执行 nuxt generate 完成无法正常渲染 html 文件

修改问题 3 后,脚本编译成功,服务可以启动,但是无法正常渲染 html 文件,html 内容全部是 500 错误

You can preview this build using node .output/server/index.mjs nitro 10:32:08
Listening on [http://localhost:3000/](http://localhost:3000/) [nuxt] [request error] Invalid module ".cache/nuxt/views/document.template" is not a valid package name imported from D:\***\.output\server\chunks\renderer.mjs
 at new NodeError (node:internal/errors:371:5)
 at parsePackageName (node:internal/modules/esm/resolve:859:11)
 at packageResolve (node:internal/modules/esm/resolve:880:5)
 at moduleResolve (node:internal/modules/esm/resolve:978:18)
 at defaultResolve (node:internal/modules/esm/resolve:1080:11)
 at ESMLoader.resolve (node:internal/modules/esm/loader:530:30)
 at ESMLoader.getModuleJob (node:internal/modules/esm/loader:251:18)
 at ModuleWrap. (node:internal/modules/esm/module_job:79:40)
 at link (node:internal/modules/esm/module_job:78:36)

原因是 .output\server\chunks\renderer.mjs 中引用错误

4: import htmlTemplate from '.cache/nuxt/views/document.template';
260: const getClientManifest = cachedImport(() => import('.cache/nuxt/dist/server/client.manifest'));

.cache/nuxt/views/document.template.cache/nuxt/dist/server/client.manifest 都是无效地址,应该是 .nuxt/view/document.template.mjs.nuxt/dist/server/client.manifest.mjs

解决办法: node_modules/nitropack/dist/chunks/prerender.mjs 生成 .output\server\chunks\renderer.mjs 时,file://***/node_modules/.cache/ 的文件要 replace 为正确路径,且不能将 .mjs 替换 replace 掉。

请原谅我知道了原因,但是没有办法通过修改代码解决,因为有点复杂能力有限,没花时间去研究了。

所以我最终的解决办法就是:降级! 关闭 bridge

打开 nuxt.config.js 添加:bridge: false

woodcoal avatar Apr 28 '22 02:04 woodcoal

Would you be able to provide a reproduction? 🙏

More info

Why do I need to provide a reproduction?

Reproductions make it possible for us to triage and fix issues quickly with a relatively small team. It helps us discover the source of the problem, and also can reveal assumptions you or we might be making.

What will happen?

If you've provided a reproduction, we'll remove the label and try to reproduce the issue. If we can, we'll mark it as a bug and prioritise it based on its severity and how many people we think it might affect.

If needs reproduction labeled issues don't receive any substantial activity (e.g., new comments featuring a reproduction link), we'll close them. That's not because we don't care! At any point, feel free to comment with a reproduction and we'll reopen it.

How can I create a reproduction?

We have a couple of templates for starting with a minimal reproduction:

👉 https://stackblitz.com/github/nuxt/starter/tree/v2-bridge 👉 https://codesandbox.io/p/github/nuxt/starter/v2-bridge-codesandbox

A public GitHub repository is also perfect. 👌

Please ensure that the reproduction is as minimal as possible. See more details in our guide.

You might also find these other articles interesting and/or helpful:

github-actions[bot] avatar Jan 05 '24 14:01 github-actions[bot]

This issue was closed because it was open for 7 days without a reproduction.

github-actions[bot] avatar Apr 18 '24 01:04 github-actions[bot]