178 votes

Angular 2+ - Définir dynamiquement la balise de base <base>

Nous avons une application d'entreprise qui utilise Angular 2 pour le client. Chacun de nos clients a leur propre URL unique, par exemple : https://our.app.com/customer-one et https://our.app.com/customer-two. Actuellement, nous sommes en mesure de définir dynamiquement le en utilisant document.location. Donc, l'utilisateur accède à https://our.app.com/customer-two et est défini sur /customer-two...parfait !

Le problème survient lorsque l'utilisateur est par exemple sur https://our.app.com/customer-two/another-page et qu'il actualise la page ou essaie d'accéder directement à cette URL, le est défini sur /customer-two/another-page et les ressources ne peuvent pas être trouvées.

Nous avons essayé ce qui suit sans succès :

    var base = document.location.pathname.split('/')[1];
    document.write('<base href="http://stackoverflow.com/' + base + '" />');

...

Malheureusement, nous sommes à court d'idées. Toute aide serait incroyable.

1 votes

Avez-vous déjà essayé quelque chose avec APP_BASE_HREF ? Je ne suis pas tout à fait sûr de la façon dont cela serait mis en œuvre, mais il semble que ce soit quelque chose qui serait utile...

0 votes

Bien sûr, cela dépend définitivement de la version du routeur que vous utilisez actuellement. Êtes-vous sur la version 3.0.0-alpha.x du routeur?

0 votes

Je suis en train d'utiliser "@angular/router": "3.0.0-alpha.7"

215voto

Zze Points 8878

La réponse marquée ici n'a pas résolu mon problème, peut-être en raison de différentes versions d'angular. J'ai pu obtenir le résultat souhaité avec la commande angular cli suivante dans le terminal / shell :

ng build --base-href /myUrl/

ng build --bh /myUrl/ ou ng build --prod --bh /myUrl/

Cela modifie le en dans la version construite uniquement ce qui était parfait pour notre changement d'environnement entre le développement et la production. Le meilleur était qu'aucune base de code ne nécessite de modification en utilisant cette méthode.


Pour résumer, laissez le href de base de votre index.html tel que : puis exécutez ng build --bh ./ avec angular cli pour en faire un chemin relatif, ou remplacez le ./ par ce que vous voulez.


Mise à jour :

Comme l'exemple ci-dessus montre comment le faire à partir de la ligne de commande, voici comment l'ajouter à votre fichier de configuration angular.json

Ceci sera utilisé pour tous les ng serving pour le développement local

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

Ceci est la configuration spécifique pour les constructions de configuration telles que prod :

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

La documentation officielle de angular-cli faisant référence à l'utilisation.

75 votes

Cette solution nécessite une construction par client, ce qui ne résout probablement pas le problème de l'OP.

1 votes

@MaximeMorin dans mon expérience jusqu'à présent, ./ fonctionne pour tous les emplacements. Donc en réalité, je ne pense pas que vous ayez à construire par client.

15 votes

@Zze Mon expérience avec ./ a été très différente. Cela fonctionne jusqu'à ce que l'utilisateur navigue vers une route et appuie sur le bouton de rafraîchissement du navigateur. À ce moment-là, nos réécritures gèrent l'appel, servent la page d'index, mais le navigateur suppose que ./ est la route actuelle et non le dossier racine de l'application web. Nous avons résolu le problème de l'OP avec un index dynamique (.aspx, .php, .jsp, etc) qui définit le href de base.

74voto

sharpmachine Points 1198

Voici ce que nous avons finalement fait.

Ajoutez ceci à index.html. Cela devrait être la première chose dans la section

  (function() {
    window['_app_base'] = '/' + window.location.pathname.split('/')[1];
  })();

Ensuite, dans le fichier app.module.ts, ajoutez { provide: APP_BASE_HREF, useValue: window['_app_base'] || '/' } à la liste des fournisseurs, comme ceci :

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 { }

1 votes

Erreur TS7017: L'élément a implicitement un type 'any' car le type "Window" n'a pas de signature d'index. useValue: (window as any) ['_app_base'] || '/' aide

0 votes

Ne fonctionne pas vraiment pour les dernières versions de ng2, y a-t-il une solution ? (charge le mauvais chemin des scripts, puis le bon chemin des scripts, mais pas sur mobile)

0 votes

En fonction de votre réponse, j'ai pu le retravailler un peu plus, de sorte que nous n'ayons pas à supprimer une fonction dans index.html.

45voto

Krishnan Points 81

Sur la base de votre réponse (@sharpmachine), j'ai pu le refactoriser un peu plus, de sorte que nous n'ayons pas à pirater une fonction dans 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 { }

Et, ./shared/common-functions.util.ts contient:

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 votes

J'ai déployé myapp dans un sous-dossier. Mon url ressemble maintenant à ceci : http://localhost:8080/subfolder/myapp/#/subfolder/myroute Est-ce que le vôtre ressemble à ça ? Savez-vous comment vous débarrasser du sous-dossier après le # pour que ça ressemble simplement à http://localhost:8080/subfolder/myapp/#/myroute ?

0 votes

Oh. Je pense que href base n'est nécessaire que pour LocationStrategy. Dans mon cas, j'utilise HashLocationStrategy. Donc je n'ai même pas besoin de le définir. Avez-vous écrit un code spécial pour gérer l'actualisation avec LocationStrategy?

1 votes

Oui, base href est seulement requis pour LocationStrategy à ma connaissance. Quant à l'écriture de code spécial pour gérer le rafraîchissement avec LocationStrategy, je ne suis pas sûr de ce que vous voulez dire exactement. Vous demandez, que se passe-t-il si mon "base href" change pendant une activité dans mon application ? Alors, oui, j'ai dû faire une chose peu orthodoxe comme window.location.href = '/' + newBaseHref; là où il était nécessaire de le changer. Je n'en suis pas très fier. De plus, pour donner une mise à jour, j'ai abandonné ces solutions de piratage dans mon application car cela posait problème au niveau du design. Les paramètres du router fonctionnent parfaitement, donc je suis resté dessus.

24voto

Daerik Points 2686

J'utilise le répertoire de travail actuel ./ lors de la construction de plusieurs applications sur le même domaine :

À noter, j'utilise .htaccess pour faciliter le routage lors du rechargement de la page :

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

2 votes

Merci beaucoup pour le fichier .htaccess

13 votes

Cette réponse est incorrecte, elle ne fonctionne pas pour les routes telles que /votre-application/a/b/c. Si vous rafraîchissez votre page à partir d'une telle route, Angular recherchera les fichiers JS principaux, de polyfills et d'exécution ainsi que le fichier CSS de styles sous /votre-application/a/b/. Ils ne se trouvent évidemment pas à cet emplacement, mais sous /votre-application/.

2 votes

@toongeorges Cette réponse a été écrite il y a presque deux ans en utilisant un fichier de configuration détecté et exécuté par le logiciel Serveur Web Apache pour gérer le routage lors du rechargement de la page. Dire que cette solution est incorrecte et ne fonctionne pas est trompeur, mais ce que vous voulez dire, c'est que vous n'avez pas réussi à le faire fonctionner avec votre configuration.

20voto

Karanvir Kang Points 111

Simplification de la réponse existante par @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 { }

Vous n'avez pas à spécifier une balise de base dans votre index.html, si vous fournissez une valeur pour le jeton opaque APP_BASE_HREF.

0 votes

Ceci est très similaire (et donc pris en charge) à la documentation officielle angular.io/api/common/APP_BASE_HREF

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X