Angular 2/4/5-ベースhrefを動的に設定


130

クライアントにAngular 2を使用するエンタープライズアプリがあります。お客様ごとに独自のURL(例:https://our.app.com/customer-oneと)がありhttps://our.app.com/customer-twoます。現在、を<base href...>使用して動的に設定できますdocument.location。したがって、ユーザーはヒットhttps://our.app.com/customer-two<base href...>/customer-two... に設定されます!

問題は、たとえばユーザーがにいてhttps://our.app.com/customer-two/another-page、ページを更新するか、そのURLに直接アクセスしようとすると、<base href...>がに設定され/customer-two/another-page、リソースが見つからないことです。

私たちは次のことを試みましたが、役に立たなかった:

<!doctype html>
<html>

<head>
  <script type='text/javascript'>
    var base = document.location.pathname.split('/')[1];
    document.write('<base href="https://stackoverflow.com/' + base + '" />');
  </script>

...

残念ながら、アイデアは新鮮です。どんな助けでも素晴らしいでしょう。


1
APP_BASE_HREFで何かを試みましたか?それがどのように実装されるかはよくわかりませんが、それは役に立つと思われます...
Jarod Moser

もちろん、現在使用しているルーターのバージョンによっても異なります。ルータバージョン3.0.0-alpha.xを使用していますか?
Jarod Moser 2016年

私は「@ angular / router」を使用しています:「3.0.0-alpha.7」
シャープマシン

5
Angular 7-2018年11月。これはまだ問題です。現在の回答は部分的な解決策を提供します。角度モジュール内での作業は遅すぎます。インデックスHTMLが提供されると、スクリプトをどこからプルするかを知る必要があります。私がそれを見る方法は2つしかありません-asp \ php \ whateverを使用して、動的なbasehrefコンテンツでindex.htmlを提供します。または、index.htmlファイルのネイティブJavaScriptを使用して、DOMコンテンツを変更する前に変更します。どちらも一般的な問題の解決策としては不十分です。悲しい。
Stavm 2018年

1
誰かが私の質問にも答えてください。stackoverflow.com/questions/53757931/...
カラン

回答:


166

ここでマークされた答えは私の問題を解決しませんでした、おそらく異なる角度のバージョン。angular cliターミナル/シェルで次のコマンドを使用して、目的の結果を得ることができました。

ng build --base-href /myUrl/

ng build --bh /myUrl/ または ng build --prod --bh /myUrl/

これにより、ビルドされたバージョンでのみが変更<base href="https://stackoverflow.com/"><base href="https://stackoverflow.com/myUrl/">れますの開発と生産の間の環境では、当社の変更のための完璧でした。最良の部分は、この方法を使用してコードベースを変更する必要がないことでした。


要約すると、index.htmlベースhref を次のように残します。<base href="https://stackoverflow.com/">次にng build --bh ./、角度cliで実行して相対パスにするか、./必要なものに置き換えます。


更新:

上記の例はコマンドラインから実行する方法を示しているので、これをangular.json構成ファイルに追加する方法です。

これはすべてng servingの地域開発に使用されます

"architect": {
    "build": {
      "builder": "@angular-devkit/build-angular:browser",
      "options": {
        "baseHref": "/testurl/",

これは、prodなどの構成ビルドに固有の構成です。

"configurations": {
   "Prod": {
     "fileReplacements": [
        {
          "replace": src/environments/environment.ts",
          "with": src/environments/environment.prod.ts"
        }
      ],
      "baseHref": "./productionurl/",

公式の angular-cli使い方を参照するドキュメント。


35
このソリューションでは、顧客ごとのビルドが必要ですが、これはおそらくOPの問題を解決していません。
Maxime Morin

1
これまでの私の経験では、@ MaximeMorinは./すべての場所で機能します。したがって、実際にはクライアントごとにビルドする必要はないと思います。
Zze

9
@Zzeでの私の経験./は非常に異なっています。これは、ユーザーがルートに移動してブラウザーの更新ボタンまたはキーを押すまで機能します。その時点で、リライトは呼び出しを処理し、インデックスページを提供しますが、ブラウザーはそれ./が現在のルートであり、Webアプリのルートフォルダーではないと想定します。ベースhrefを設定する動的(.aspx、.php、.jspなど)インデックスでOPの問題を解決しました。
Maxime Morin

2
--prodビルド中に使用してもbase href値は変わりません。ここでそれについて話すことはできません。--prod伝えangular-cli使用するenvironment.prod.tsデフォルトのファイルの代わりにファイルをenvironment.ts自分の中にenvironmentsフォルダ
Mattew永劫

1
@MattewEon --prod彼らはOPでの展開について話していたので、それがフラグと互換性があることを示すだけでした。
Zze

57

これが私たちがやったことです。

これをindex.htmlに追加します。それは<head>セクションの最初のものであるべきです

<base href="https://stackoverflow.com/">
<script>
  (function() {
    window['_app_base'] = '/' + window.location.pathname.split('/')[1];
  })();
</script>

次に、app.module.tsファイル{ provide: APP_BASE_HREF, useValue: window['_app_base'] || '/' }で次のようにプロバイダーのリストに追加します。

import { NgModule, enableProdMode, provide } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { APP_BASE_HREF, Location } from '@angular/common';


import { AppComponent, routing, appRoutingProviders, environment } from './';

if (environment.production) {
  enableProdMode();
}

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    HttpModule,
    routing],
  bootstrap: [AppComponent],
  providers: [
    appRoutingProviders,
    { provide: APP_BASE_HREF, useValue: window['_app_base'] || '/' },
  ]
})
export class AppModule { }

エラーTS7017:型 'Window'にはインデックスシグネチャがないため、要素には暗黙的に 'any'型があります。useValue: (window as any) ['_app_base'] || '/'助け
エルカンBuelbuel

最新のng2では実際に機能しません。解決策はありますか?(不正なスクリプトパスをロードしてから、適切なスクリプトパスをロードしますが、モバイルではロードしません)
Amit

1
コンテンツの長さがコメントに対して長すぎるため、以下の回答として追加してください。
クリシュナン2017年

1
@Amit最新のng2で簡単に解決するには、以下の私の回答を参照してください。
Zze

3
他のファイルの問題をどのように解決しましたか?私のブラウザーはlocalhost:8080 / main.bundle.jsを読み込もうとしていますが、私のcontextPathが異なるために読み込めません。(localhost:8080 / hello / main.bundle.jsをフェッチする必要があります
Sasa

33

(@sharpmachine)の回答に基づいて、さらにリファクタリングすることができたため、で関数をハックアウトする必要はありませんindex.html

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { APP_BASE_HREF, Location } from '@angular/common';

import { AppComponent } from './';
import { getBaseLocation } from './shared/common-functions.util';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    HttpModule,
  ],
  bootstrap: [AppComponent],
  providers: [
    appRoutingProviders,
    {
        provide: APP_BASE_HREF,
        useFactory: getBaseLocation
    },
  ]
})
export class AppModule { }

そして、./shared/common-functions.util.ts含まれています:

export function getBaseLocation() {
    let paths: string[] = location.pathname.split('/').splice(1, 1);
    let basePath: string = (paths && paths[0]) || 'my-account'; // Default: my-account
    return '/' + basePath;
}

1
myappをサブフォルダーにデプロイしました。私のURLは次のようになります: http://localhost:8080/subfolder/myapp/#/subfolder/myrouteこれはあなたのようですか?#の後にサブフォルダーを削除して、それをそのままにする方法を知っていますhttp://localhost:8080/subfolder/myapp/#/myrouteか?
techguy2000

ああ。hrefbaseはLocationStrategyにのみ必要だと思います。私の場合、私はHashLocationStrategyを使用しています。だから私はそれを設定する必要さえありません。LocationStrategyで更新を処理するための特別なコードを書きましたか?
techguy2000 2017

1
はい、AFAIKにbase hrefのみ必要ですLocationStrategy。LocationStrategyで更新を処理するための特別なコードを書くことに関しては、正確に何を意味しているのかわかりません。アプリでのアクティビティ中に「base href」が変更された場合はどうなりますか?それから、はい、window.location.href = '/' + newBaseHref;それが変更される必要がある場所のような汚いことをしなければなりませんでした。私はそれをあまり誇りに思っていません。また、更新を行うために、アプリのこれらのハックソリューションから離れました。それは私にとってデザインの問題になっていたためです。ルーターパラメータは完全に正常に機能するため、こだわりました。
クリシュナン2017

1
あなたは何appRoutingProviderクリシュナン、のような外観は?受け入れられた回答も同じように使用されているのがわかります。多分あなたは彼のをコピーしただけですprovidersが、そうでない場合は、サンプルを提供したり、その目的を説明したりできますか?唯一のドキュメントimportsモジュールをルーティングするには、それは(これまで私が見ることができるようにと)任意のルーティング関連のプロバイダを使用していません
赤エンドウ

@Krishnanは、ここで私はそれを動作させるためにnginxのとしなければならないものです:location /subfolder/myapp/ { try_files $uri /subfolder/myapp/index.html; } location /subfolder2/myapp/ { try_files $uri /subfolder2/myapp/index.html; }
techguy2000

24

./同じドメインから複数のアプリをビルドするときは、現在の作業ディレクトリを使用します。

<base href="./">

.htaccess余談ですが、ページのリロード時のルーティングを支援するために使用します。

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.html [L]

2
.htaccessファイルをありがとうございました
Shahriar Siraj Snigdho 2018年

8
この答えは不正解です。/your-app/a/b/cなどのルートでは機能しません。このようなルートからページを更新すると、Angularはランタイム、ポリフィル、メインのJSファイル、およびスタイルのCSSファイルを/ your-app / a / b /の下で探します。彼らは明らかにその場所ではなく、/ your-app /の下にあります
toongeorges

2
@toongeorgesこの回答は、ページのリロード時のルーティングを処理するためにApache Webサーバーソフトウェアによって検出および実行される構成ファイルを使用して、約2年前に書かれました。このソリューションは正しくなく機能しないと言うのは誤解を招きますが、構成で機能させる方法を理解できなかったということです。
Daerik、

私はApacheの書き換えルールを見落としていて、これがApacheで機能しないと言うほど十分に知らないので、私は間違っているかもしれず、あなたの答えは正しいかもしれません。いずれにしても、ここでは複数の回答が提供されているため、サーバー構成を変更する必要のないソリューションを好みます。これにより、アプリケーションが異なるサーバー間で移植可能になるためです。
toongeorges

2
いや、@ toongeorgesは正しいです。に変更するの<base href="./">は間違っており/app/a/b/c、実際にテストしただけのようなルートに干渉します。Webアプリのみを扱う場合は、base hrefを自分で設定するか、デプロイ時にbase hrefを変更する角度のある方法を確認してください(これについては多くの回答があります)。
giovannipds

15

@sharpmachineによる既存の回答の簡略化

import { APP_BASE_HREF } from '@angular/common';
import { NgModule } from '@angular/core';

@NgModule({
    providers: [
        {
            provide: APP_BASE_HREF,
            useValue: '/' + (window.location.pathname.split('/')[1] || '')
        }
    ]
})

export class AppModule { }

APP_BASE_HREF不透明トークンの値を提供する場合は、index.htmlでベースタグを指定する必要はありません。


10

これは、実稼働環境ではうまく機能します

<base href="https://stackoverflow.com/" id="baseHref">
<script>
  (function() {
    document.getElementById('baseHref').href = '/' + window.location.pathname.split('/')[1] + "/";
  })();
</script>

2
このソリューションには、IISでの複数のVDセットアップに大きな制限があります。チャンクが重複して読み込まれます。
Karan

9

angular4では、.angular-cli.jsonアプリでbaseHrefを構成することもできます。

.angular-cli.json

{   ....
 "apps": [
        {
            "name": "myapp1"
            "baseHref" : "MY_APP_BASE_HREF_1"
         },
        {
            "name": "myapp2"
            "baseHref" : "MY_APP_BASE_HREF_2"
         },
    ],
}

これにより、index.htmlのベースhrefがMY_APP_BASE_HREF_1に更新されます

ng build --app myapp1

4
これはまた、各アプリのビルドを作成する必要があります。
Patrick Hillert、

6

Angular CLI 6を使用している場合は、angular.jsonのdeployUrl / baseHrefオプションを使用できます(プロジェクト> xxx>アーキテクト>ビルド>構成>プロダクション)。このようにして、プロジェクトごとにbaseUrlを簡単に指定できます。

ビルドされたアプリのindex.htmlを見て、設定が正しいことを確認します。


7
これには、すべての影響を含む、環境ごとに異なるビルドが必要です。
Stavm 2018年

3

アドオン:たとえば、/ usersをルーターのアプリケーションベースとして、/ publicをアセットの使用ベースとして

$ ng build -prod --base-href /users --deploy-url /public

1

同様の問題がありましたが、実際には自分のWeb内にあるファイルの存在を調査することになりました。

probePathは、チェックするファイルへの相対URL(正しい場所にいる場合はマーカーの種類)です(例: 'assets / images / thisImageAlwaysExists.png')。

<script type='text/javascript'>
  function configExists(url) {
    var req = new XMLHttpRequest();
    req.open('GET', url, false); 
    req.send();
    return req.status==200;
  }

  var probePath = '...(some file that must exist)...';
  var origin = document.location.origin;
  var pathSegments = document.location.pathname.split('/');

  var basePath = '/'
  var configFound = false;
  for (var i = 0; i < pathSegments.length; i++) {
    var segment = pathSegments[i];
    if (segment.length > 0) {
      basePath = basePath + segment + '/';
    }
    var fullPath = origin + basePath + probePath;
    configFound = configExists(fullPath);
    if (configFound) {
      break;
    }
  }

  document.write("<base href='" + (configFound ? basePath : '/') + "' />");
</script>

-1

率直に言って、あなたのケースは私にはうまくいきます!

Angular 5を使用しています。

<script type='text/javascript'>
    var base = window.location.href.substring(0, window.location.href.toLowerCase().indexOf('index.aspx'))
    document.write('<base href="' + base + '" />');
</script>

このソリューションはあなたのために働きましたか?私は問題に直面しています。私の投稿にも返信してください。stackoverflow.com/questions/53757931/...
カラン

1
:document.writeを()を使用して避けてくださいdevelopers.google.com/web/updates/2016/08/...
パトリックHillert

-6

私はちょうど変わりました:

  <base href="/">

これに:

  <base href="/something.html/">

/で終わることを忘れないでください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.