【发布时间】:2020-04-22 05:52:17
【问题描述】:
我在 Angular Web 应用中有不同的路线,例如“/about”、“/contact”等。
运行 build:ssr 后,我运行 ng run myproject:prerender
这将完成并在/dist/myproject/browser/* 中创建文件夹。每条路线都有不同的文件夹。
每个文件夹中都有一个 index.html 文件,它是渲染的 HTML 路由。到目前为止一切顺利。
但是,在每个 index.html 呈现的文件中,第一行如下所示:
<html lang="en"><head><script src="runtime-es2015.c9afb3256f2870e161de.js" type="module"></script><script src="runtime-es5.c9afb3256f2870e161de.js" nomodule="" defer=""></script><script src="polyfills-es5.2878b91c9d9c0a1ee890.js" nomodule="" defer=""></script><script src="polyfills-es2015.4cfd8e3e2fd9d10b9e9e.js" type="module"></script><script src="vendor-es2015.429669b901f4df42a057.js" type="module"></script><script src="vendor-es5.429669b901f4df42a057.js" nomodule="" defer=""></script><script src="main-es2015.a676e1a4bb3cc6e8a80c.js" type="module"></script><script src="main-es5.a676e1a4bb3cc6e8a80c.js" nomodule="" defer=""></script>
这看起来很好,直到您意识到脚本 src 是相对的。
因此,当部署时,假设https://myproject.com/about 将从 /about/ 文件夹加载呈现的 index.html。但是在加载脚本的时候,因为src是相对的,所以脚本路径变成了:https://myproject.com/about/runtim-es2015....js。
这会返回 404 并使应用程序崩溃,因为该文件夹中不存在脚本。这些脚本位于根目录中。
这有意义吗?
我通过在我的部署管道中编写并包含以下脚本创建了一个临时修复程序,该脚本将正斜杠添加到 src 路径:
const { readdirSync } = require('fs')
const fs = require('fs')
const getDirectories = source =>
readdirSync(source, { withFileTypes: true })
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name)
const loop = function (DirectoryString) {
const Dirs = getDirectories(DirectoryString);
if (Dirs.length) {
Dirs.forEach(folderName => {
const DirectoryStr = './dist/myproject/browser/' + folderName + '/';
if (fs.existsSync(DirectoryStr)) {
console.log(DirectoryStr + 'index.html Fixed');
loop(DirectoryStr);
fs.readdir(DirectoryStr, (err, files) => {
files.forEach(file => {
if (file === "index.html") {
const fileName = `${DirectoryStr}index.html`;
try {
fs.readFile(fileName, 'utf8', function (err, data) {
if (err) {
return console.log(err);
} else {
var result = data.replace(/script src\=\"(?!http)([a-zA-Z])/g, 'script src="/$1');
fs.writeFile(fileName, result, 'utf8', function (err) {
if (err) return console.log(err);
});
}
});
} catch (e) {
console.log(e);
}
}
});
});
}
});
}
}
loop('./dist/myproject/browser/');
这行得通,但是现在,我想要一种在 Angular 中解决此问题的方法。我找不到其他有同样问题的人。有什么建议吗?
更新
在 localhost 开发中有时也会出现此问题。可以这么说,如果路线的深度不止一条,就会发生这种情况。
所以 ng 服务器会自动重新加载 localhost:4200/order/step2(由更新代码触发),应用程序没有加载,我收到错误
GET http://localhost:4200/order/step2/runtime.js net::ERR_ABORTED 404 (Not Found)
这对于开发来说是相当烦人的。这个项目从来不习惯,最近才开始:(
更新 2
另外,我在查看 localhost 呈现页面的源代码时观察到,脚本标签被添加到文档之外。
从顶部开始,这是文档的渲染源:
<script src="runtime.js" type="module"></script><script src="polyfills.js" type="module"></script><script src="styles.js" type="module"></script><script src="vendor.js" type="module"></script><script src="main.js" type="module"></script><!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
为什么 Angular 会这样做?
更新 3
我的文档头中有<base href="/">,但我怀疑由于脚本标签是在基础声明之前和文档之外添加的,所以基础没有被应用。
更新 4
这里是重现该问题的 github 存储库:
【问题讨论】:
-
尝试在
angular.json文件的prerender目标的options部分添加"deployUrl": "/", -
@David 没用。失败并出现错误
Schema validation failed with the following errors: Data path "" should NOT have additional properties(deployUrl). -
你在 github 上有一个可以重现问题的小项目吗?
-
对不起,
deployUrl设置有误,您需要将其添加到 angular.json 文件的build目标的production配置中。我试过这个,当我运行ng run project:prerender:production时,它会将/添加到 index.html 中的脚本路径中,如果它应该应用于其他配置,您可以对其他配置执行相同的操作。但是我不确定为什么您的脚本被添加到页面顶部... -
如果您查看 dist 文件夹中预渲染的
index.html文件,它们是否在文件顶部base标记之前也有脚本?愚蠢的问题,您是否有一些代码可以创建/移动可能有问题的 dom 元素 (appendChild/renderer/...)?