外部のインラインインデクスをロードし、角度でSSRでロードする
18230 ワード
前の記事では、AppCount Initlizerトークンを使用しましたload external configurations via HTTP . 今日、私は設定をより近くに持ってきます.しかし、どのように、我々は角のアプリケーションでJSONをHTMLに注入しますか?
実装は2つのターゲットを満たす必要があります. 設定をコンパイルされたソースに含めることはできません.したがって、直接入力することはできません.
これはローカルインポートを除外します:
私たちはタイピングを維持したい JSONがセキュリティ上の注意のためHTMLに注入されないので、設定スクリプトを作成します.
JavaScriptの設定をインポートせずにインポートする唯一の場所は、直接HTMLヘッダにあります.それは設計時にチェックされない唯一の場所です、そして、ランタイムで沈黙404をスローします.
このようにします.
をつくりましょう
FIXへの最初の問題は
しかし、極端な場合は以下のように局所的に生成されます. リモートサーバから設定をロードする 追加 そして、おそらくスクリプトの前に
このリスナーの主な問題は、ルータが解決した後に発火するということです.
トークンの返却が重要でないので、プラットフォーム初期化装置では、以前にロードすることができます.あなたは注意しなければならないが
我々が使うならば
イン
ビルド後のサーバー出力フォルダwhere the express app is defined , the
しかし、設定を待ちます.jsファイルに
解決策つのプラットホームでNULLであるプロパティをチェックします.最も簡単なプロパティは
まず、あなたのエクスプレスサーバファイルで
次に、ホスト設定ファイル( server/localdata/config . js )にあります.
HTMLでなければなりません
JSONファイルではなく、constを持つjsです.
それはローカルでなければなりません、リモートはあまりに遅いです、そして、継ぎ目の側で働きません. *SSRには余分な荷物が必要です
私はHTTPメソッドが好き!SSRで利用することができますが、1つのトリックは、SSRのためのHTMLエンジンのレンダリングオプションのJSONを提供することができます.それは何が必要ですか?何を修正する必要がありますか?来週お話しましょう.より良い制御のための角から完全にサーバーコードを分離する方法とともに.
Angular Express Engine PLATFORM_INITIALIZER StackBlitz App Defer attribute on MDN
実装は2つのターゲットを満たす必要があります.
これはローカルインポートを除外します:
import * as WebConfig from '/localdata/config.json';
またはモジュールスクリプト<script type="module" src="/localdata/config.js">
または動的モジュール読み込みimport('./localdata/config.js')
.then((config) => {
// do something with config
});
config
使用する前に使用できません.// configs/config.js file, named it "WebConfig" to avoid confusion
const WebConfig = {
isServed: true,
API: {
apiRoot: 'url/server/app',
},
MyKey: 'MyValue',
};
スクリプトを注入する
JavaScriptの設定をインポートせずにインポートする唯一の場所は、直接HTMLヘッダにあります.それは設計時にチェックされない唯一の場所です、そして、ランタイムで沈黙404をスローします.
このようにします.
<script src="localdata/config.js"></script>
このパスを動作させるには、angular.json assets
が必要です.I make it a habit to name things differently just to remember that the rule exists.
{ //... angular.json
"assets": [
{
"glob": "*",
"input": "configs",
"output": "/localdata"
}
]
AppRank初期化子の実装
をつくりましょう
APP_INITIALIZER
最低限の応答void
. ここではConfigService
// declare WebConfig
declare const WebConfig: any;
export const configFactory = (config: ConfigService): (() => void) => {
return () => config.loadAppConfig();
};
@Injectable({
providedIn: 'root',
})
export class ConfigService {
constructor() {}
// set a static member for easier handling
private static _config: IConfig;
static get Config(): IConfig {
return this._config || Config;
}
private _createConfig(config: any): IConfig {
// cast all keys as are, extend local Config
const _config = { ...Config, ...(<IConfig>config) };
// set static member
ConfigService._config = _config;
return _config;
}
loadAppConfig(): void {
// here is the JavaScript variable... is it ready?
if (WebConfig?.isServed) {
this._createConfig(WebConfig);
} else {
// not loaded? fall back
console.log('error');
this._createConfig(Config);
}
}
}
課題
FIXへの最初の問題は
WebConfig
, 同じサービスファイルにconstを宣言するdeclare const WebConfig: any;
もう一つの問題は、遅い構成の極端な場合です.スクリプトがdefer
プロパティをブロックしてはならず、localdata
同じサーバーから提供* *それは十分に速くする必要があります*.しかし、Stackblitzでは、それはあまりに遅いです.私はそのトラックを下っていません、なぜなら、「リモートコンフィグをローカルにロードするのを待つ」ことに注意しなければならないなら、私たちはHTTPメソッドでより良いです.しかし、極端な場合は以下のように局所的に生成されます.
async
属性<script src="https://saphire.sekrab.com/localdata/config.js" async></script>
…The WebConfig
最初に値がないので、「未定義」エラーをスローします.それを修正するには、index.html
または任意のJavaScriptでコードに追加しました.<script>
window.WebConfig = {
isServed: false,
};
</script>
AppRangeブートストラップリスナーの実装
このリスナーの主な問題は、ルータが解決した後に発火するということです.
プラットフォーム初期化の実装
トークンの返却が重要でないので、プラットフォーム初期化装置では、以前にロードすることができます.あなたは注意しなければならないが
defer
そして、ローカル滞在.( ps . Stackblitzではこのメソッドを使用できません)export const platformFactory = (): (() => void) => {
ConfigService.loadAppConfig(); // static element
return () => null;
};
インmain.ts
platformBrowserDynamic([
{
provide: PLATFORM_INITIALIZER,
useFactory: platformFactory,
multi: true,
}
]).bootstrapModule(AppBrowserModule)
このトークンは依存性を使わないので、ConfigService
静的要素のグループであるので、どこにでもそれを提供する必要はありません.書き直してテストしましょう.// notice it no longer needs to be injected
export class ConfigService {
private static _config: IConfig;
static get Config(): IConfig {
return this._config || Config;
}
private static _createConfig(config: any): IConfig {
// cast all keys as are
const _config = { ...Config, ...(<IConfig>config) };
// set static member
ConfigService._config = _config;
return _config;
}
static loadAppConfig(): void {
if (WebConfig?.isServed) {
this._createConfig(WebConfig);
} else {
// error
this._createConfig(Config);
}
}
}
ちょうどローカルにしましょう.<script src="localdata/config.js" defer></script>
静的要素をどこでも参照するのと同じくらい簡単です.ConfigService.Config.isServed
以来、ルータの解決もテストに耐えるdefer
属性はパース後にJavaScriptを読み込みますDOMContentLoaded
. クライアント側では、すべてが動作します.今SSRに.SSR
我々が使うならば
APP_INITIALIZER
(静的メソッドを使用すると、トークンはまだAppModule
, どちらのプラットフォームでも共有できます.我々が使うならばPLATFORM_INITIALIZER
, に注入されましたplatformBrowserDynamic
ブラウザプラットフォームのみを実行します.SSRのために、サーバープラットホームで注入される必要があります.イン
server.ts
, ブートストラップAppServerModule
オプションとして発生するngExpressEngine , これには別のオプションがあります.providers array
, これはトークンが提供されている場所です.// in server.ts, or where you create the ngExpressEngine
export const AppEngine = ngExpressEngine({
bootstrap: AppServerModule,
// pass provider here
providers:[
{
provide: PLATFORM_INITIALIZER,
useFactory: platformFactory,
multi: true,
}
]
});
それは十分ではない.現在WebConfig
サーバ側では未定義です.ビルド後のサーバー出力フォルダwhere the express app is defined , the
WebConfig
変数はグローバルコンテキストで設定する必要があります.インNodeJs
(全部使っているわけじゃないかな?と同じくらい簡単ですglobal.WebConfig
global.WebConfig = require('./localdata/config.js');
The localdata
この場合、サーバーフォルダがあります.jsファイル.しかし、設定を待ちます.jsファイルに
exports
動作する行のステートメント.また、それはexports
ステートメントを水和後ブラウザで実行する!解決策つのプラットホームでNULLであるプロパティをチェックします.最も簡単なプロパティは
window
. ( 1つを作成することができますが、コードの5倍のコードを受け取ります.まず、あなたのエクスプレスサーバファイルで
global.window = undefined
.次に、ホスト設定ファイル( server/localdata/config . js )にあります.
// in config.js add the following lines
if (!window) {
module.exports = WebConfig;
}
がある.今、configファイルはブラウザとサーバープラットフォームで動作します.挑戦
HTMLでなければなりません
config.js
からconfig.prod.js
あなたは最終的になりますindex.dev.html
and index.html
生産のために.JSONファイルではなく、constを持つjsです.
それはローカルでなければなりません、リモートはあまりに遅いです、そして、継ぎ目の側で働きません.
StackBlitz project does not run Angular universal, nevertheless, the source code includes SSR
戻る、HTTPへ
私はHTTPメソッドが好き!SSRで利用することができますが、1つのトリックは、SSRのためのHTMLエンジンのレンダリングオプションのJSONを提供することができます.それは何が必要ですか?何を修正する必要がありますか?来週お話しましょう.より良い制御のための角から完全にサーバーコードを分離する方法とともに.
資源
Reference
この問題について(外部のインラインインデクスをロードし、角度でSSRでロードする), 我々は、より多くの情報をここで見つけました https://dev.to/ayyash/loading-external-configurations-inline-and-in-ssr-in-angular-31joテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol