首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Angular5 (从AngularJS迁移)的服务器端呈现

使用Angular5 (从AngularJS迁移)的服务器端呈现
EN

Stack Overflow用户
提问于 2018-04-23 08:56:02
回答 3查看 507关注 0票数 7

我们正在将应用程序从AngularJS转换为Angular5。我试图找出如何使用Angular5 -复制一些行为,即使用服务器端呈现来创建可注入的值.

在我们当前的Angular1.6应用程序中,我们有以下index.hbs文件:

代码语言:javascript
复制
<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>Collaborative Tool</title>
  <link href="favicon.ico" rel="shortcut icon" type="image/x-icon">
</head>

<body class="aui content" ng-app="app">

  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js"></script>

  <script>

    /* globals angular */
    angular.module('app')
      .value('USER', JSON.parse('{{{user}}}'))
      .value('WORKSTREAM_ENUM', JSON.parse('{{{workStreamEnum}}}'))
      .value('CATEGORY_ENUM', JSON.parse('{{{categoryEnum}}}'))
      .value('ROLES_ENUM', JSON.parse('{{{roles}}}'))
      .value('FUNCTIONAL_TEAM_ENUM', JSON.parse('{{{functionalTeams}}}'))
      .value('CDT_ENV', '{{CDT_ENV}}')
      .value('CDT_HOST', '{{CDT_HOST}}')
      .value('CDT_LOGOUT_URL', '{{CDT_LOGOUT_URL}}');


  </script>

</body>
</html>

所以我们要做的是在第一个脚本标记中加载角,然后使用第二个脚本标记创建一些值/enum/常量。本质上是使用服务器端呈现(工具栏)将数据发送到前端。

我的问题是:是否有一些与Angular5非常相似的方法?我们如何使用服务器端呈现在Angular5?中创建可注入的模块/值?

EN

回答 3

Stack Overflow用户

发布于 2018-05-01 05:01:17

我的团队在从AngularJS过渡到Angular (v2的早期发布候选版本)时也遇到了同样的问题。我们提出了一个解决方案,我们仍然使用,我不知道任何更新,以使它更容易(至少当不使用角环球-如果您正在使用,然后有内置的东西来引导初始数据)。通过序列化JSON对象并将其设置为HTML中app根角组件上的属性,我们将数据传递给我们的角应用程序:

代码语言:javascript
复制
<app-root [configuration]="JSON_SERIALIZED_OBJECT"></app-root>

其中JSON_SERIALIZED_OBJECT是实际的序列化对象。我们使用.NET (非核心,因此角环球并不是一个真正的选项)来呈现我们的页面(执行[configuration]="@JsonConvert.SerializeObject(Model.Context)"),所以不知道您需要做什么,但是看起来您应该能够做与之前序列化它相同的事情。

一旦安装完毕,我们必须在我们的主要应用程序组件中手动地JSON.parse(...)该对象,但是我们把它当作一个角度输入。这就是我们的组件抓取它的样子:

代码语言:javascript
复制
import { Component, ElementRef } from '@angular/core';
import { ConfigurationService } from 'app/core';

@Component(...)
export class AppComponent {
    constructor(private element: ElementRef, private configurationService: ConfigurationService) {
        this.setupConfiguration();
    }

    private setupConfiguration() {
        const value = this.getAttributeValue('[configuration]');
        const configuration = value ? JSON.parse(value) : {};

        this.configurationService.setConfiguration(configuration);
    }

    private getAttributeValue(attribute: string) {
        const element = this.element.nativeElement;

        return element.hasAttribute(attribute) ? element.getAttribute(attribute) : null;
    }
}

如图所示,我们使用一个服务来共享系统周围的数据。它可以是这样简单的东西:

代码语言:javascript
复制
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

import { Configuration } from './configuration.model';

@Injectable()
export class ConfigurationService {
    private readonly configurationSubject$ = new BehaviorSubject<Configuration>(null);
    readonly configuration$ = this.configurationSubject$.asObservable();

    setConfiguration(configuration: Configuration) {
        this.configurationSubject$.next(configuration);
    }
}

然后,在需要配置数据的组件中,注入此服务并监视更改。

代码语言:javascript
复制
import { Component, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/takeUntil';

import { ConfigurationService } from 'app/core';

@Component(...)
export class ExampleThemedComponent implements OnDestroy {
    private readonly destroy$ = new Subject<boolean>();

    readonly theme$: Observable<string> = this.configurationService.configuration$
        .takeUntil(this.destroy$.asObservable())
        .map(c => c.theme);

    constructor(private configurationService: ConfigurationService) {
    }

    ngOnDestroy() {
        this.destroy$.next(true);
    }
}

注意:我们有时在运行时对我们的配置进行更改,这就是为什么我们使用一个主题和可观察的。如果您的配置不会改变,那么您可以跳过这些示例的所有部分。

票数 4
EN

Stack Overflow用户

发布于 2018-05-01 05:29:23

在服务器端呈现依赖项时,仍然可以在组件内部使用依赖项注入。

如果您计划使用带有角5的服务器端呈现,您应该考虑查看角万向,它为在服务器端呈现角单页应用程序提供了构建块(对于SEO友好的可索引内容)。

有许多良好的角万向节项目在那里。[universal-starter][2]就是一个很好的例子。它使用ngExpressEngine在请求的url上动态呈现应用程序。它使用webpack项目配置,其中包含一个预发布任务,该任务编译您的应用程序并预先录制您的应用程序文件。此任务如下所示:

代码语言:javascript
复制
// Load zone.js for the server.
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import {readFileSync, writeFileSync, existsSync, mkdirSync} from 'fs';
import {join} from 'path';

import {enableProdMode} from '@angular/core';
// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();

// Import module map for lazy loading
import {provideModuleMap} from '@nguniversal/module-map-ngfactory-loader';
import {renderModuleFactory} from '@angular/platform-server';
import {ROUTES} from './static.paths';

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const {AppServerModuleNgFactory, LAZY_MODULE_MAP} = require('./dist/server/main.bundle');

const BROWSER_FOLDER = join(process.cwd(), 'browser');

// Load the index.html file containing referances to your application bundle.
const index = readFileSync(join('browser', 'index.html'), 'utf8');

let previousRender = Promise.resolve();

// Iterate each route path
ROUTES.forEach(route => {
  var fullPath = join(BROWSER_FOLDER, route);

  // Make sure the directory structure is there
  if(!existsSync(fullPath)){
    mkdirSync(fullPath);
  }

  // Writes rendered HTML to index.html, replacing the file if it already exists.
  previousRender = previousRender.then(_ => renderModuleFactory(AppServerModuleNgFactory, {
    document: index,
    url: route,
    extraProviders: [
      provideModuleMap(LAZY_MODULE_MAP)
    ]
  })).then(html => writeFileSync(join(fullPath, 'index.html'), html));
});

稍后,您可以运行一个快速服务器,该服务器呈现应用程序生成的HTML:

代码语言:javascript
复制
app.engine('html', ngExpressEngine({
  bootstrap: AppServerModuleNgFactory,
  providers: [
    provideModuleMap(LAZY_MODULE_MAP)
  ]
}));

app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));

// Server static files from /browser
app.get('*.*', express.static(join(DIST_FOLDER, 'browser'), {
  maxAge: '1y'
}));

// All regular routes use the Universal engine
app.get('*', (req, res) => {
  res.render('index', { req });
});

// Start up the Node server
app.listen(PORT, () => {
  console.log(`Node Express server listening on http://localhost:${PORT}`);
});

您可以运行服务器端特定的代码,例如:

代码语言:javascript
复制
import { PLATFORM_ID } from '@angular/core';
 import { isPlatformBrowser, isPlatformServer } from '@angular/common';

 constructor(@Inject(PLATFORM_ID) private platformId: Object) { ... }

 ngOnInit() {
   if (isPlatformBrowser(this.platformId)) {
      // Client only code.
      ...
   }
   if (isPlatformServer(this.platformId)) {
     // Server only code.
     ...
   }
 }

但请注意,该窗口、文档、导航器和其他浏览器类型--服务器上不存在。因此,任何可能使用这些的库都可能无法工作。

票数 4
EN

Stack Overflow用户

发布于 2018-05-01 05:42:24

创建文件: data.ts。在这个文件中,声明变量及其类型(我只显示一个变量),并为每个变量创建InjectionToken

代码语言:javascript
复制
import { InjectionToken } from '@angular/core';

// describes the value of the variable
export interface EmbeddedUserData {
  userId: string;
  // etc
}

// tells the app that there will be a global variable named EMBEDDED_USER_DATA (from index.html)
export declare const EMBEDDED_USER_DATA: EmbeddedUserData;

// creates injection token for DI that you can use it as a provided value (like value or constant in angular 1)
export UserData = new InjectionToken<EmbeddedUserData>('EmbeddedUserData');

然后来到您的app.module.ts并提供以下标记:

代码语言:javascript
复制
// ...
providers: [
  { provide: UserData, useValue: EMBEDDED_USER_DATA }
],
// ...

最后,将其用作任何正常的服务/注入值:

代码语言:javascript
复制
// ...
constructor(@Inject(UserData) userData: EmbeddedUserData) {}
// ...

或者将其用作简单的导入变量(在本例中甚至不需要提供/注入任何内容):

代码语言:javascript
复制
import { EMBEDDED_USER_DATA } from './data.ts';

因此,你几乎和你在安古拉杰的情况一样。剩下的唯一方法是在角脚本之前将变量添加到index.html中(也许把变量放在head中也是有意义的):

代码语言:javascript
复制
<script>var EMBEDDED_USER_DATA = JSON.parse({ ... })</script>
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49976990

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档