将基本 Angular 2 个应用程序部署到 Google App Engine

Deploying basic Angular 2 app to Google App Engine

我可以使用 Angular 2 创建基本的前端应用程序,并且可以使用 python 在 Google App Engine 上使用端点创建后端。然而,我似乎无法弄清楚如何将两者放在一起并使用云 SDK 进行部署。

这是一个基本示例,我什至无法在 GAE 上托管没有后端调用的简单 angular2 应用程序。我在使用 angular2 CLI 构建后获取了 dist 文件夹,并尝试使用 app.yaml 文件连接到它。它似乎在浏览器开发人员 (dev_appserver.py app.yaml) 中工作,尽管我在 SDK 中收到一些 404 错误,我认为 GET 请求与我的 index.html 文件有关。然后,我创建了一个空白的 index.yaml 文件并尝试部署它,但在 appspot.com 位置出现了 404 错误。这是 app.yaml 文件:

application:
version:
runtime: python27
threadsafe: true
api_version: 1

handlers:
- url: /favicon\.ico
  static_files: favicon.ico
  upload: favicon\.ico

- url: (.*)/
  static_files: dist/index.html
  upload: dist

- url: (.*)
  static_files: dist
  upload: dist

我真的不知道我做错了什么。我需要某种 main.application python 后端来连接到 dist 文件吗?我是否需要包含节点模块或来自 Angular2 的其他类型或文件?任何帮助将不胜感激!谢谢

将您的 app.yaml 替换为以下内容。它会起作用的!

application: you-app-name-here
version: 1
runtime: python
api_version: 1

default_expiration: "30d"

handlers:
- url: /(.*\.(appcache|manifest))
  mime_type: text/cache-manifest
  static_files: static/
  upload: static/(.*\.(appcache|manifest))
  expiration: "0m"

- url: /(.*\.atom)
  mime_type: application/atom+xml
  static_files: static/
  upload: static/(.*\.atom)
  expiration: "1h"

- url: /(.*\.crx)
  mime_type: application/x-chrome-extension
  static_files: static/
  upload: static/(.*\.crx)

- url: /(.*\.css)
  mime_type: text/css
  static_files: static/
  upload: static/(.*\.css)

- url: /(.*\.eot)
  mime_type: application/vnd.ms-fontobject
  static_files: static/
  upload: static/(.*\.eot)

- url: /(.*\.htc)
  mime_type: text/x-component
  static_files: static/
  upload: static/(.*\.htc)

- url: /(.*\.html)
  mime_type: text/html
  static_files: static/
  upload: static/(.*\.html)
  expiration: "1h"

- url: /(.*\.ico)
  mime_type: image/x-icon
  static_files: static/
  upload: static/(.*\.ico)
  expiration: "7d"

- url: /(.*\.js)
  mime_type: text/javascript
  static_files: static/
  upload: static/(.*\.js)

- url: /(.*\.json)
  mime_type: application/json
  static_files: static/
  upload: static/(.*\.json)
  expiration: "1h"

- url: /(.*\.m4v)
  mime_type: video/m4v
  static_files: static/
  upload: static/(.*\.m4v)

- url: /(.*\.mp4)
  mime_type: video/mp4
  static_files: static/
  upload: static/(.*\.mp4)

- url: /(.*\.(ogg|oga))
  mime_type: audio/ogg
  static_files: static/
  upload: static/(.*\.(ogg|oga))

- url: /(.*\.ogv)
  mime_type: video/ogg
  static_files: static/
  upload: static/(.*\.ogv)

- url: /(.*\.otf)
  mime_type: font/opentype
  static_files: static/
  upload: static/(.*\.otf)

- url: /(.*\.rss)
  mime_type: application/rss+xml
  static_files: static/
  upload: static/(.*\.rss)
  expiration: "1h"

- url: /(.*\.safariextz)
  mime_type: application/octet-stream
  static_files: static/
  upload: static/(.*\.safariextz)

- url: /(.*\.(svg|svgz))
  mime_type: images/svg+xml
  static_files: static/
  upload: static/(.*\.(svg|svgz))

- url: /(.*\.swf)
  mime_type: application/x-shockwave-flash
  static_files: static/
  upload: static/(.*\.swf)

- url: /(.*\.ttf)
  mime_type: font/truetype
  static_files: static/
  upload: static/(.*\.ttf)

- url: /(.*\.txt)
  mime_type: text/plain
  static_files: static/
  upload: static/(.*\.txt)

- url: /(.*\.unity3d)
  mime_type: application/vnd.unity
  static_files: static/
  upload: static/(.*\.unity3d)

- url: /(.*\.webm)
  mime_type: video/webm
  static_files: static/
  upload: static/(.*\.webm)

- url: /(.*\.webp)
  mime_type: image/webp
  static_files: static/
  upload: static/(.*\.webp)

- url: /(.*\.woff)
  mime_type: application/x-font-woff
  static_files: static/
  upload: static/(.*\.woff)

- url: /(.*\.xml)
  mime_type: application/xml
  static_files: static/
  upload: static/(.*\.xml)
  expiration: "1h"

- url: /(.*\.xpi)
  mime_type: application/x-xpinstall
  static_files: static/
  upload: static/(.*\.xpi)

# image files
- url: /(.*\.(bmp|gif|ico|jpeg|jpg|png))
  static_files: static/
  upload: static/(.*\.(bmp|gif|ico|jpeg|jpg|png))

# audio files
- url: /(.*\.(mid|midi|mp3|wav))
  static_files: static/
  upload: static/(.*\.(mid|midi|mp3|wav))  

# windows files
- url: /(.*\.(doc|exe|ppt|rtf|xls))
  static_files: static/
  upload: static/(.*\.(doc|exe|ppt|rtf|xls))

# compressed files
- url: /(.*\.(bz2|gz|rar|tar|tgz|zip))
  static_files: static/
  upload: static/(.*\.(bz2|gz|rar|tar|tgz|zip))

# index files
- url: /(.+)/
  static_files: static//index.html
  upload: static/(.+)/index.html
  expiration: "15m"

- url: /(.+)
  static_files: static//index.html
  upload: static/(.+)/index.html
  expiration: "15m"

# site root
- url: /
  static_files: static/index.html
  upload: static/index.html
  expiration: "15m"

您的正则表达式匹配似乎在错误的位置。试试这个格式:

handlers:
- url: /favicon\.ico
  static_files: favicon.ico
  upload: favicon\.ico
- url: /
  static_files: dist/index.html
  upload: dist/index.html
- url: /(.*)
  static_files: dist/
  upload: dist/(.*)

这来自测试和我们在创建 Static Hosting tutorial on App Engine 时遇到的一些奇怪情况。

我现在将我的 app.yaml 文件中的处理程序更新为如下所示,以便静态上传到 google 云平台。如果正则表达式不是这样,Angular 路由器就会出现问题。 Dist 文件夹是从 angular cli ng build:

输出的
handlers:
- url: /favicon.ico
  static_files: dist/favicon.ico
  upload: dist/assets/favicon.ico

- url: /(.*\.(gif|png|jpg|css|js)(|\.map))$
  static_files: dist/
  upload: dist/(.*)(|\.map)

- url: /(.*)
  static_files: dist/index.html
  upload: dist/index.html

更新:

对于生产 ng build --prod,这是我的 app.yaml 文件的样子:

runtime: python27
threadsafe: true
api_version: 1

handlers:
- url: /(.*\.(gif|png|jpeg|jpg|css|js|ico))$
  static_files: dist/
  upload: dist/(.*)
- url: /(.*)
  static_files: dist/index.html
  upload: dist/index.html

我会将 dist 文件夹中的任何其他文件类型添加到第一个处理程序中的正则表达式分组字符:(gif|png|jpeg|jpg|css|js|ico)

对于 Angular 4 和 App Engine 的最新版本,我构建了以下内容:

service: stage
runtime: python27
api_version: 1
threadsafe: true

skip_files:
- ^(?!dist)  # Skip any files not in the dist folder

handlers:
# Routing for bundles to serve directly
- url: /((?:inline|main|polyfills|styles|vendor)\.[a-z0-9]+\.bundle\.js)
  secure: always
  redirect_http_response_code: 301
  static_files: dist/
  upload: dist/.*

# Routing for a prod styles.bundle.css to serve directly
- url: /(styles\.[a-z0-9]+\.bundle\.css)
  secure: always
  redirect_http_response_code: 301
  static_files: dist/
  upload: dist/.*

# Routing for typedoc, assets and favicon.ico to serve directly
- url: /((?:assets|docs)/.*|favicon\.ico)
  secure: always
  redirect_http_response_code: 301
  static_files: dist/
  upload: dist/.*

# Any other requests are routed to index.html for angular to handle so we don't need hash URLs
- url: /.*
  secure: always
  redirect_http_response_code: 301
  static_files: dist/index.html
  upload: dist/index\.html
  http_headers:
    Strict-Transport-Security: max-age=31536000; includeSubDomains
    X-Frame-Options: DENY

正在寻求有关如何改进的反馈。

首先通过 运行 执行以下命令构建您的 angular 项目

--ng build prod

构建完成后,在项目的根文件夹中创建一个 app.yaml 文件并粘贴以下代码:

# [START runtime]
runtime: python27
threadsafe: yes
# [END runtime]

handlers:

- url: /(.+)
 static_files: dist/
 upload: dist/(.*)

- url: /
 static_files: dist/index.html
 upload: dist/index.html

# Temporary setting to keep gcloud from uploading not required files for 
deployment
skip_files:
- ^node_modules$
- ^app\.yaml
- ^README\..*
- \.gitignore
- ^\.git$
- ^grunt\.js
- ^src$
- ^e2e$
- \.editorconfig
- ^karma\.config\.js
- ^package\.json
- ^protractor\.conf\.js
- ^tslint\.json

在此之后 运行:

gcloud app deploy

对于Angular6,文件结构有所改变。以下内容基于@Rob 的回答,但针对启用了 service-worker 的 Angular 6 进行了更新。请务必将 "my-app" 替换为您应用的文件夹名称。

service: stage
runtime: python27
api_version: 1
threadsafe: true

skip_files:
- ^(?!dist)  # Skip any files not in the dist folder

handlers:
# Routing for bundles to serve directly
- url: /((?:runtime|main|polyfills|styles|vendor)\.[a-z0-9]+\.js)
  secure: always
  redirect_http_response_code: 301
  static_files: dist/my-app/
  upload: dist/my-app/.*

# Routing for bundle maps to serve directly
- url: /((?:runtime|main|polyfills|styles|vendor)\.[a-z0-9]+\.js\.map)
  secure: always
  redirect_http_response_code: 301
  static_files: dist/my-app/
  upload: dist/my-app/.*

# Routing for a prod styles.bundle.css to serve directly
- url: /(styles\.[a-z0-9]+\.css)
  secure: always
  redirect_http_response_code: 301
  static_files: dist/my-app/
  upload: dist/my-app/.*

# Routing for typedoc, assets, and favicon.ico to serve directly
- url: /((?:assets|docs)/.*|favicon\.ico)
  secure: always
  redirect_http_response_code: 301
  static_files: dist/my-app/
  upload: dist/my-app/.*

# Routing for service worker files serve directly
- url: /(manifest\.json|ngsw\.json|ngsw-worker\.js|safety-worker\.js|worker-basic\.min\.js|ngsw_worker\.es6\.js\.map)
  secure: always
  redirect_http_response_code: 301
  static_files: dist/my-app/
  upload: dist/my-app/.*

# Any other requests are routed to index.html for angular to handle so we don't need hash URLs
- url: /.*
  secure: always
  redirect_http_response_code: 301
  static_files: dist/my-app/index.html
  upload: dist/my-app/index\.html
  http_headers:
    Strict-Transport-Security: max-age=31536000; includeSubDomains
    X-Frame-Options: DENY

如果您使用自定义字体,可以使用此模板:

handlers:
  # Routing for bundles to serve directly
  - url: /(.*\.(gif|png|jpeg|jpg|css|js|ico))$
    static_files: dist/
    upload: dist/(.*)

  - url: /assets/fonts/(.*\.(eot|woff|woff2|svg))$
    static_files: dist/assets/fonts/
    upload: dist/assets/fonts/(.*)

  - url: /.*
    static_files: dist/index.html
    upload: dist/index.html