Angular 模板上的 .NET Core 2.1 基本 href 标签 [英] .NET core 2.1 base href tag on Angular template

查看:25
本文介绍了Angular 模板上的 .NET Core 2.1 基本 href 标签的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在 .NET Core 2.1 + Angular 5 模板的基础上为我们的团队构建一个模板,该模板包含在最新版本的 Core 2.1 中,我们将应用程序部署到虚拟文件夹中,例如/it/myapp 或/aa/myotherapp

I'm building a template for our team on top of the .NET Core 2.1 + Angular 5 template included in the latest release of core 2.1, we deploy applications into virtual folders, for example /it/myapp, or /aa/myotherapp

在 2.0 模板上,base href 属性将自动设置,我假设是因为它是用 razor 构建的,如下所示:

On the 2.0 template the base href property would be set automatically, I'm assuming because it was built with razor, like this:

<base href="~/" />

然而这对于 2.1 模板来说不是真的,我假设这是因为模板实际上只使用静态文件,新的 app.UseSpa()

However this is not true for the 2.1 template, I'm assuming it's because the template actually only uses static files, with the new app.UseSpa()

关于如何自动填充基本 href 标签的任何想法?

Any ideas on how I could automatically populate the base href tag?

谢谢

推荐答案

是的,我知道这是一个老问题,但我希望这能帮助更多人.答案是关于 Angular 6 和 .NET Core 2.1.忠告:解释有点大(抱歉)

Yes, I know it's an old question, but I hope this help someone more. The answer is about Angular 6 and .NET Core 2.1. Advice: the explanation is a bit large (sorry)

在 Core 2.1 中,我们有一个典型的 Startup.cs

In Core 2.1, we have a tipical Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
     }
     app.UseHttpsRedirection();
     app.UseStaticFiles();
     app.UseMvc(routes =>
     {
          routes.MapRoute(
          name: "default",
          template: "{controller}/{action=Index}/{id?}");
      });
      app.UseSpa(spa =>
      {
           // To learn more about options for serving an Angular SPA from ASP.NET Core,
           // see https://go.microsoft.com/fwlink/?linkid=864501

           spa.Options.SourcePath = "ClientApp";
           spa.Options.DefaultPage = $"/index.html";

           if (env.IsDevelopment())
           {
               spa.UseAngularCliServer(npmScript: "start");
           }
      });
  }

最重要的是

   spa.UseAngularCliServer(npmScript: "start");

这告诉 .NET 使用 package.json 中定义的脚本

this tell to .NET that use the script defined in package.json

{
  "name": "client-app",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve --base-href=/ --serve-path=/", //<--this line
    "build": "ng build",
     ...
  },
  ....
}

看到我们有两个选择.--base-href 和 --serve-path

See that we have two options. --base-href and --serve-path

当我们执行应用程序时,我们收到一个 index.html 之类的

When we execute the application, we received an index.html like

<!DOCTYPE html>
<html>
<head>
  <title>Angular i18n example</title>
  <base href="/"
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <app-root>Loading...</app-root>
    <script type="text/javascript" src="runtime.js"></script>
    <script type="text/javascript" src="polyfills.js"></script>
    <script type="text/javascript" src="styles.js"></script>
    <script type="text/javascript" src="vendor.js"></script>
    <script type="text/javascript" src="main.js"></script>
</body>
</html>

我们可以更改基本的 href 更改我们的 package.json.但是如果不改变 --serve-path ,我们的应用程序就会失败,因为我们正在根据 base href 寻找脚本.

We can change the base href change our package.json. But if not change the --serve-path according, our app fails because we are looking for the script according to the base href.

这个想法是脚本不依赖于 base href.我希望脚本的 src 位于绝对路径中.这就是脚本变得像

The idea is that the scripts not depending for base href. I want that the src of scripts was in absolute path. That's the scripts becomes like

    <script type="text/javascript" src="/<serve-path>/runtime.js"></script>
    <script type="text/javascript" src="/<serve-path>/polyfills.js"></script>
    <script type="text/javascript" src="/<serve-path>/styles.js"></script>
    <script type="text/javascript" src="/<serve-path>/vendor.js"></script>
    <script type="text/javascript" src="/<serve-path>/main.js"></script>

所以,如果我们在 .html 中写一些类似的内容

So, if we write in our .html some like

<head>
  <title>Angular i18n example</title>
  <script>
     var str = document.location.href;
     ...
     document.write('<base href="' + str+ '" />');
  </script>
  <!--we remove base href="/"
      <base href="/"
  -->
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

我们的脚本正在从正确的路径中寻找并且应用程序可以正常工作.¿如何改变添加脚本的方式?好吧,我们必须在两个文件中进行一些更改:

Our scripts are looking for from the correct path and the application works. ¿How change the way to add the scripts? Well, we have to make a few changes in two files:

  • index-html-webpack-plugin.js 来自node_modules@angular-devkituild-angularsrcangular-cli-filesplugins

  • index-html-webpack-plugin.js from node_modules@angular-devkituild-angularsrcangular-cli-filesplugins

browser.js 来自node_modules@angular-devkituild-angularsrcangular-cli-filesmodelswebpack-configs

browser.js from node_modules@angular-devkituild-angularsrcangular-cli-filesmodelswebpack-configs

首先查看 index-html-webpack-plugin.js 中的类 IndexHtmlWebpackPlugin

See first the class IndexHtmlWebpackPlugin in index-html-webpack-plugin.js

class IndexHtmlWebpackPlugin {
    constructor(options) {
        this._options = Object.assign({ input: 'index.html', output: 'index.html', entrypoints: ['polyfills', 'main'], sri: false }, options);
    }
    apply(compiler) {
      ....
        const scriptElements = treeAdapter.createDocumentFragment();
        for (const script of scripts) {
            const attrs = [
                { name: 'type', value: 'text/javascript' },
                //change the line
                //{ name: 'src', value: (this._options.deployUrl || '') + script },
                //by 
                { name: 'src', value: (this._options.baseHref)+(this._options.deployUrl || '') + script },
            ];
            if (this._options.sri) {
                const content = compilation.assets[script].source();
                attrs.push(...this._generateSriAttributes(content));
            }
            const element = treeAdapter.createElement('script', undefined, attrs);
            treeAdapter.appendChild(scriptElements, element);
        }

看看我们如何将 this._options.baseHref 添加到脚本中好吧,实际上在构造函数中我们没有baseHref,这是因为我们必须更改文件browser.js在

see how we add the this._options.baseHref to the scripts Well, really in constructor we haven't baseHref, it is for we must change the file browser.js in

plugins: extraPlugins.concat([
    new index_html_webpack_plugin_1.IndexHtmlWebpackPlugin({
        input: path.resolve(root, buildOptions.index),
        output: path.basename(buildOptions.index),
        baseHref: buildOptions.baseHref,
        entrypoints: package_chunk_sort_1.generateEntryPoints(buildOptions),
        deployUrl: buildOptions.deployUrl,
        //we add this line
        servePath: buildOptions.servePath,
        sri: buildOptions.subresourceIntegrity,
    }),
]),

还有一步.当我们在 index.html 中使用 javascript 编写基本标签时,我们不希望 angular-cli 添加此标签.为此,我们唯一需要更改的是注释 index-html-webpack-plugin.js 中的行

One more step. As we are writen the base tag using javascript in our index.html, we don't want that angular-cli add this tag. For this, the only thing that we must change is comment the lines in index-html-webpack-plugin.js

// Adjust base href if specified
if (typeof this._options.baseHref == 'string') {
    let baseElement;
    for (const headChild of headElement.childNodes) {
        if (headChild.tagName === 'base') {
            baseElement = headChild;
        }
    }
    const baseFragment = treeAdapter.createDocumentFragment();
    if (!baseElement) {
        baseElement = treeAdapter.createElement('base', undefined, [
            { name: 'href', value: this._options.baseHref },
        ]);
//coment the two lines below
//        treeAdapter.appendChild(baseFragment, baseElement);
//        indexSource.insert(headElement.__location.startTag.endOffset + 1, parse5.serialize(baseFragment, { treeAdapter }));
    }

仅此而已!!

另外两个兴趣点

当我们使用 javascript 创建基础标签时,我们需要调整基础标签.否则,如果我们刷新页面,我们的基本 href 就会发生变化,如果是这样,例如在主页中,我们的 url 将类似于 http://www.dominio.com/<某事>/<东西>/家.我们希望基地继续 <某事>/<东西>.看一下脚本,然后按照您的需要,例如

When we create the base tag using javascript we need ajust the base. Else, if we refresh the page, our base href change and, if we are, e.g in page home, our url will be like http:// www.dominio.com/< something>/< something>/home. We want that the base will go on < something>/< something>. take a look to the script and ajust like your want,e.g.

  <script>
    var items = document.location.href.split('/');
    while (items.length>4)
      items.pop();
    document.write('<base href="' + items.join('/') + '" />');
  </script>

最后一点,如果只有有效的 url 是作为 SPA 的服务器.为此,我们修改了我们的 startup.cs 使只有有效的 url 是服务器.(或者,一些像 http://www.dominio.com/patata/patata 的网址服务我们的水疗中心)在 app.UseMvc 和 app.UseSpa 之间添加一个中间件

The last point if make that only valid url are server as SPA. For that, we modified our startup.cs make that only valid url was server. (else, some url like http://www.dominio.com/patata/patata serve our SPA) Add between app.UseMvc and app.UseSpa a Middleware

   app.UseMvc(routes =>
   {
    ...
    });
   //Add this Middleware
    app.Use(async (context, next) =>
    {
        string path = context.Request.Path.Value.Substring(1);
        bool encontrado = path.EndsWith(".js") || path.EndsWith(".css") || path.EndsWith(".map") || path.StartsWith("sockjs");
        if (!encontrado)
        {
            //make here the check for the pages
            //"silly" e.g.
            encontrado==(path=="es/adminitrator" || path=="it/administrator")
        }
        if (encontrado)
            await next.Invoke();
        else
        {
            context.Response.ContentType = "text/html";
            await context.Response.SendFileAsync(Path.Combine(env.WebRootPath, "error404.html"));
        }
        app.UseSpa(spa=>
        {
              ....
        }
    });

更新

使用 java 脚本添加标签库,这是一个非常丑陋的解决方法.更好地使用BASE_REF Provider

Use java script to add tab base it's a really ugly work-around. Better use BASE_REF Provider

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

@NgModule({
  providers: [{provide: APP_BASE_HREF, useValue: '/my/app'}]
})
class AppModule {}

这篇关于Angular 模板上的 .NET Core 2.1 基本 href 标签的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆