- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我创建这篇文章是为了从社区中获得一些见解。
不久前,随着 .NET Core 3.0 的发布,广为人知且广泛使用的用法 spa.UseSpaPrerendering
已被标记为过时。
大约在 2019 年初,我在一个使用 Angular 但需要 SEO 和更好的加载性能的项目中使用 .NET Core 实现了 SSR。
1 年后(现在,2020 年初),他们希望在不同的项目中也有同样的情况。但它已经使用了 Core 3.1。我们立即注意到了 Depricated 标志,所以我开始寻找自己做的方法。
根据过去的经验,SSR 问题有两部分,第一部分是让您的 Angular 应用程序能够在服务器端实际运行。因此,摆脱或解决所有无法在服务器端执行的东西(解决窗口 API 的使用,通过在 Angular 中使用 isPlatform 东西)。第二部分是实际让 .NET Core 启动 Angular CLI 以开始实际的预渲染。这是使用 UseSpaPrerendering
完成的.
分析告诉我们自己解决问题的文档并检查我过去的代码,事情实际上开始变得有意义了。
我查看了 package.json 文件中的命令,执行的 2 个主要命令是 build:ssr
实际预编译整个 server/main.js 旁边的 browser/... 文件。第二个命令是 serve:ssr
,这将由 UseSpaPrerendering
执行代码(至少这是我的假设)。
在实践中,我们的 CI/CD 会去执行 build:ssr
并将所有文件发布到运行 .NET Core 运行时的应用服务器。并使用 UseSpaPrerendering
然后它会执行 serve:ssr
的代码.
现在跳到我需要找到解决方案的现在。我想我也可以自己运行必要的命令。所以在我的 Angular 中排除了一些非 SSR 兼容的代码后,我运行了 build:ssr
命令我自己,然后是 serve:ssr
命令。效果很好,我的 Angular 应用程序是 SSR 渲染的,由节点本身而不是 .NET Core 提供。
下一步是我在我的 .NET Core 启动文件中尝试过。现在我做了 build:ssr
我自己(因为在生产中它将由 CI/CD 完成)并且我重新编写了 start
脚本在我的 package.json 中运行命令 npm run serve:ssr
.我使用 spa.UseAngularCliServer(npmScript: "start");
启动了该命令代码在我的 startup.cs 中,我有它,我的 .NET Core 运行时启动我的 API 和我的 SSR Angular 应用程序。
到目前为止一切顺利,但现在只有 1 个问题。我的 SSR Angular 默认托管在端口 4000 上,并且还监听该端口(我可以在输出中看到),而我的 API 监听端口 5000(http) 和 5001(https)。
所以现在我有几个关于这个的问题:
最佳答案
对于任何面临这个问题的人,我刚刚解决了它,这是我们的解决方案,但事实很少:
/***************************************************************************************************
* Load `$localize` onto the global scope - used if i18n tags appear in Angular templates.
*/
import { APP_BASE_HREF } from '@angular/common';
import '@angular/localize/init';
import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { existsSync } from 'fs';
import { join } from 'path';
import 'zone.js/dist/zone-node';
import { environment } from './environments/environment';
// THIS FIX MOST OF THE COMMON ISSUES WITH SSR:
// FIRST SET THE BROWSER PATH ACCORDING TO RUNTIME ENVIRONMENT
let browserPath;
if (environment.production) {
browserPath = '../browser';
} else {
browserPath = 'dist/browser';
}
const enDistFolder = join(process.cwd(), browserPath + '/en');
// Emulate browser APIs
const domino = require('domino');
const fs = require('fs');
const templateA = fs.readFileSync(join(enDistFolder, 'index.html')).toString();
const win = domino.createWindow(templateA);
console.log('win');
win.Object = Object;
console.log('Object');
win.Math = Math;
console.log('Math');
global['window'] = win;
global['document'] = win.document;
global['Event'] = win.Event;
console.log('declared Global Vars....');
/****************************************************/
/** NOTE THIS: I need to avoid sorting this line */
// USE CTRL+P -> SAVE WITHOUT FORMATTING
import { AppServerModule } from './main.server';
/****************************************************/
// The Express app is exported so that it can be used by serverless Functions.
export function app() {
const server = express();
const indexHtml = existsSync(join(browserPath, 'index.original.html')) ? 'index.original.html' : 'index.html';
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));
server.set('view engine', 'html');
server.set('views', browserPath);
// Example Express Rest API endpoints
// server.get('/api/**', (req, res) => { });
// Serve static files from /browser
server.get('*.*', express.static(browserPath, {
maxAge: '1y'
}));
server.use('/robots.txt', express.static('/en/robots.txt'));
server.use('/ads.txt', express.static('/en/ads.txt'));
// THE ORIGINAL Universal Requests handler
// // // All regular routes use the Universal engine
// // server.get('*', (req, res) => {
// // res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
// // });
// OUR i18n REQUESTS HANDLER
// All regular routes use the Universal engine
server.get('*', (req, res) => {
// this is for i18n
const supportedLocales = ['en', 'es'];
const defaultLocale = 'es';
const matches = req.url.match(/^\/([a-z]{2}(?:-[A-Z]{2})?)\//);
// check if the requested url has a correct format '/locale' and matches any of the supportedLocales
const locale = (matches && supportedLocales.indexOf(matches[1]) !== -1) ? matches[1] : defaultLocale;
res.render(`${locale}/index.html`, { req });
});
return server;
}
function run() {
const port = process.env.PORT || 4000;
// Start up the Node server
const server = app();
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run();
}
export * from './main.server';
关于c# - 关于 .NET Core 3.1 和 Angular SSR spa.UseS Prerendering 替代方案的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59747892/
以下代码位于 Login.aspx 文件内。之前的代码运行起来非常流畅。但是,在添加 ajax ModalPopup 扩展程序后,发生了此错误。 当用户单击超链接“忘记密码”时,我试图创建一个弹出窗口
我遵循了以下指南: 角度: $locationProvider.html5Mode(true); 在 html 中,添加此元 header : 配置 Apache : Rewrite
我对 Java Web 完全陌生,但我的问题是: 1) 如何在 prerender() 函数中向 JSF 页面 (webuijsf) 添加新控件?2)如何更改已使用视觉设计器添加的元素的位置?也在 p
关于设置的信息: 我已经在我自己的服务器 Ubuntu 16 上成功安装了 prerender ( https://github.com/prerender/prerender)。 这是我的 .hta
我正在尝试确定是否可以在母版页 PreRender 事件中读取脚本标记。我有 CSS 链接,但到目前为止脚本标签还没有成功。 这会获取 CSS 链接: foreach (var c in HeadEl
所以我正在尝试设置 prerender.io对于我的带有 ExpressJS 后端的 AngularJS 应用程序,遵循此 tutorial .我完全按照指示做了,唯一的区别是我启用了 HTML5mo
我正在通过 react-rails(1.0.0pre) 对 React.js 和 Rails 进行试验,并且在预呈现依赖于窗口大小的响应元素时遇到了一些麻烦。每当我创建一个使用窗口的组件时,我都会收到
我正在尝试使用 prerender.io 中间件为正确的 SEO 设置我的 MEAN 堆栈应用程序。在本地,一切都很好。在生产中,nada。该应用程序托管在 OpenShift 上。我正在为 preR
我最近尝试做 Prerender,需要一些启发。我尝试预呈现我的一些页面,但加载失败。 在 chrome://net-internals/#prerender 中它会显示不支持的方案。 我在我的 ht
我正在尝试 chrome 中的预呈现功能,但是当我检查网络时,我可以看到任何链接的请求都被取消了。 我正在使用以下语法: 我在 http://prerender-test.appspot.com/
最近我注意到,Page_PreRender 事件没有被触发。如 protected override void OnPreRender使用 - 一切都很好。 AutoWire 已启用并且相同的代码在另
所以我使用带有“基线”布局的 vuetify(来自文档:https://vuetifyjs.com/en/examples/layouts/baseline)。我将一页设置为预渲染: config
您知道在 PreRender 事件上向页面添加控件有什么缺点吗? 请不要回答“取决于你的情况”我是在一般情况下说的:-) 最佳答案 PreRender事件发生在控件事件之后,因此控件不能使用任何事件。
在页面 A 上,我动态插入一个指向页面 B 的预渲染标记: . 我想知道是否 prerender当完成加载页面 B 时触发一个事件,我可以从页面 A 上的 javascript 访问该页面。 如果浏览
谁能告诉我为什么我会在下面的跟踪中收到错误? “SetFocus 只能在 PreRender 之前和期间调用。” 错误消息表明必须在 PreRender 之前或期间调用“SetFocus”,并且根据跟
我正在使用 prerender.io 为 Angular 单页应用程序进行服务器端渲染。 添加了 ngMeta 依赖并动态添加了标题和描述元标记。 添加了包含所有 URL 的 sitemap.xml
我正在尝试在我的 ASP.NET 应用程序中实现 Prerender.io。我配置了所有必需的必要步骤,包括 1) 在 Index.html 的头部 2) 配置模块 3)
我用带有 expressJS 后端的 AngularJS 制作了一个应用程序。现在我想让它可抓取,我找到了 prerender.io .我认为我所做的一切都是正确的,但由于某种原因我在预渲染器仪表板中
在让 Google 抓取工具解析我们的 AngularJS 网站时出现一些问题后,我们使用 Prerender 来提供抓取工具友好版本的页面。 此方法运行良好 - 除了网站站长工具表明我们的网站速度因
我正在尝试在服务器上运行构建。但是使用预渲染,会出现以下错误。在桌面版的ubuntu和macOS上,没有这个问题,只是服务器端的问题。我在不同的服务器上试过。 95% emittingError: F
我是一名优秀的程序员,十分优秀!