混合的 AngularJS/Angular 应用由于 Angular 13+ 移除 deployURL 而出现问题。

huangapple go评论78阅读模式
英文:

Hybrid angularjs/angular app broken due to angular 13+ removal of deployURL

问题

更新于2023年7月6日,我相信我已经确定问题是由于我的应用程序的混合性质引起的,而不仅仅是我先前假设的升级angular。

我有一个混合的angular/angularjs应用程序,目前将所有客户端文件构建到一个名为/client/的目录中。
该目录之外的所有调用都由我的后端处理。我的当前配置使用deployUrl='/client/'来适当地为该目录中的所有资源请求添加前缀。

我正在升级angular,因此deployUrl现在已被弃用/移除,我正在尝试找出如何使其继续工作。

我尝试设置我的angular.json文件中的baseHref='/client/',如此处建议:
https://stackoverflow.com/questions/71695674/what-is-best-way-to-go-about-replacing-deployurl-in-angular-json-for-v13

对于资源来说,这很有效,但它破坏了应用程序的angularjs部分。特别是当angularjs的$location尝试解析初始URL时,它会引发错误。例如,假设初始URL为https:/example.com/home,当angularjs尝试解析它时,它会抛出以下错误:

Error: [$location:ipthprfx] Invalid url "https://example.com/home", missing path prefix "https://example.com/client/".

此链接指向angular文档中的此错误

显然,angularjs不喜欢baseHref,这在以前并不是问题,因为deployUrl不需要baseHref。然而,现在我不能使用它,我似乎也不能设置baseHref来绕过问题,因为angularjs与其不兼容。

您有任何想法如何设置/构建我的应用程序,以使angular和angularjs两部分都能正常工作吗?(是的,我很想摆脱所有的angularjs代码,我们正在逐步做这个工作,但我们仍然在ajs中有大量遗留代码)。

英文:

UPDATED 7/6/2023 as I believe I have determined the issue is due to the hybrid nature of my application and not just upgrading angular as I previously assumed.

I have a hybrid angular/angularjs app that currently builds all the client files into a /client/ directory.
All calls outside of that directory are handled by my back end. My current configuration uses deployUrl='/client/' to prefix all asset requests appropriately for that directory.

I am upgrading angular, and so deployUrl is now deprecated/removed, and I am trying to figure out how to make this continue to work.

I have tried setting my angular.json baseHref='/client/', like recommended here:
https://stackoverflow.com/questions/71695674/what-is-best-way-to-go-about-replacing-deployurl-in-angular-json-for-v13

and that works fine for the assets, but it breaks the angularjs portion of the app. In particular, when angularjs $location attempts to parse the initial url, it gives an error. Ie, Assume the initial url is https:/example.com/home, when ajs tries to parse it, it throws this error:

Error: [$location:ipthprfx] Invalid url "https://example.com/home", missing path prefix "https://example.com/client/".

Which links to this error in the angular docs.

Apparently angularjs doesn't like the baseHref, which wasn't previously a problem as deployUrl didn't require a baseHref. However, now that I can't use it, I can't seem to do the workaround of setting baseHref either, since angularjs doesn't work well with it.

Any ideas how I can set up/build my app so that both the angular and angularjs portions work? (Yes, I would love to get rid of all the angularjs code, and we are doing so slowly, but we still have a lot of legacy code in ajs).

答案1

得分: 0

我们可以分享一个示例,您如何调用后端?

我们使用baseHref选项提供一个Angular应用程序,并像下面这样调用后端:

this.http.get(`/v1/resource`);

这个方法运行良好。可能是前导的 / 很重要。

英文:

Can you share an example, how you call your backend?
We serve an angular application with the baseHref option and call the backend like

this.http.get(`/v1/ressource`);

that works fine. It might be the leading / that is important.

答案2

得分: 0

我不知道这对你是否有效,但我们有一个类似的设置(混合应用程序),我们的做法如下:

  1. 在一个模块中设置APP_BASE_HREF提供者(我们为此声明了AppRoutingModule),并将其包含在AppModuleimports中:
// app-routing.module.ts
import { APP_BASE_HREF, ... } from '@angular/common';
// ...
@NgModule({
    imports: [RouterModule.forRoot(routes, {
            // enableTracing: !environment.production,
        })
    ],
    exports: [RouterModule],
    providers: [
        { provide: APP_BASE_HREF, useValue: '/' },
        { provide: LocationStrategy, useClass: ... 你的策略 ... }
    ],
    declarations: []
})
export class AppRoutingModule {
}

// app.module.ts
@NgModule({
    imports: [
        AppRoutingModule,
        // ...
    ],
    // ...
})
export class AppModule {/*...*/}
  1. index.html中设置你的路径为:<base href="/client/">
  2. 在npm配置中,在package.json中,为servee2e命令设置--serve-path选项。例如:ng serve --serve-path '/client/' --port 4300。但你也可以在angular.json中的serve配置中设置这个选项:
// angular.json
// projects -> your-project -> architect -> serve -> options
{
  "servePath": "/client/"
}

此外,值得一提的是,在我们的Cypress配置中,我们有:

// cypress.config.ts
export default defineConfig({
  env: {
    baseUrl: 'http://localhost:4300/client/' // 根据你的位置策略,可以加上或不加上'#'
  }
});

只是出于好奇
我们有一个更新的项目(不再是混合式的),上述设置也适用于纯Angular 14应用程序。但出于好奇,我尝试将APP_BASE_HREF更改为/client/,看看会发生什么。

  1. 在我们的混合应用程序中,当转到新路由时,它会重复出现/client/。旧的(AngularJS)似乎可以正常工作。
  2. 在我们的新应用程序(非混合式)中,似乎不会影响任何内容,因此//client/似乎都可以正常工作(但我只是在本地尝试过,没有在生产环境中尝试,所以不敢百分之百确定)。
英文:

I don't know if this will work for you too, but we have a similar setup (hybrid application) and what we do is:

  1. Setup up the APP_BASE_HREF provider in a module (we're declaring the AppRoutingModule for this) and include it in the imports of AppModule:
// app-routing.module.ts
import {APP_BASE_HREF, ...} from &#39;@angular/common&#39;;
// ...
@NgModule({
    imports: [RouterModule.forRoot(routes, {
            // enableTracing: !environment.production,
        })
    ],
    exports: [RouterModule],
    providers: [
        {provide: APP_BASE_HREF, useValue: &#39;/&#39;},
        {provide: LocationStrategy, useClass: ... your strategy ...}
    ],
    declarations: []
})
export class AppRoutingModule {
}

// app.module.ts
@NgModule({
    imports: [
        AppRoutingModule,
        // ...
    ],
    // ...
})
export class AppModule {/*...*/}
  1. On index.html set your path with: &lt;base href=&quot;/client/&quot;&gt;
  2. On the npm config, in package.json, we set the option --serve-path for the serve and e2e commands. Example ng serve --serve-path &#39;/client/&#39; --port 4300. But you can also set this option on the configuration(s) for serve inside angular.json:
// angular.json
// projects -&gt; your-project -&gt; architect -&gt; serve -&gt; options {
&quot;servePath&quot;: &quot;/client/&quot;

Also, worth mentioning, in our cypress configuration we have:

// cypress.config.ts
export default defineConfig({
  env: {
    baseUrl: &#39;http://localhost:4300/client/&#39;   // with or without the &#39;#&#39; depending  on your location strategy.
  }
});

Just for curiousity
We have a newer project (not on hybrid anymore) and the settings above work on a pure Angular 14 app too. But out of curiosity, I tried out and changed APP_BASE_HREF to /client/ to see what would happen.

  1. In our hybrid application, it duplicates the /client/ when changing into newer routes. The older (angularJS) seem to work.
  2. In our newer app (non hybrid), it doesn't seem to affect anything, so apparently / and /client/ would work (but I just tried this locally and not on production though, so I'm not 100% sure).

答案3

得分: 0

这是我最终解决问题的方法。我发帖只是为了以防其他人也感兴趣,尽管我不能完全推荐这个解决方案,因为$browser在技术上是一个私有的AngularJS对象,所以它不是设计用于修改/调整的,甚至没有文档记录。然而,这个解决方案对我们有效,而且我们可以接受在底层发生一些ajs更改并破坏事情的风险,尤其是因为ajs现在发生的更改不多。

我基本上重写了默认的$browser.baseHref()方法,将其返回为'/',而不是在index.html中通过<base href="..."/>指定的值。这样,我仍然可以在Angular构建期间指定baseHref,以便所有客户端资源/脚本都可以正确找到,但AngularJS的$location行为和ajs ui路由不会因此而混淆。

我将这个添加到我的AngularJS引导程序的应用程序配置部分:

$provide.decorator('$browser', ['$delegate', ($delegate) => {

  $delegate.baseHref = function replacementBaseHref() {
    return '/';
  };

  return $delegate;
}]);
英文:

This is how I ended up solving the problem. I am posting this just in case anyone else is interested, though I can't necessarily recommend this solution because $browser is technically a private angularjs object, so it isn't designed to be modified/tweaked, and isn't even documented. However, the solution worked for us, and we are okay with the risk of ajs changing something under the covers and breaking things, particularly because not that many changes are happening to ajs nowadays.

I basically overrode the default $browser.baseHref() method to return '/' rather than the value specified via <base href="..."/> in the index.html. That way, I could still specify a baseHref during the angular build, so all the client assets/resources/scripts are found correctly, but the angularjs $location behavior and ajs ui router is not confused by it.

I added this to the app config portion of my angularjs bootstrap:

$provide.decorator(&#39;$browser&#39;, [&#39;$delegate&#39;, ($delegate) =&gt; {

  $delegate.baseHref = function replacementBaseHref() {
    return &#39;/&#39;;
  };

  return $delegate;
}]);

huangapple
  • 本文由 发表于 2023年6月30日 05:14:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/76584639.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定