填寫這份《一分鐘調查》,幫我們(開發組)做得更好!去填寫Home

部署

Deployment

當你準備把 Angular 應用部署到遠端伺服器上時,有很多可選的部署方式。

When you are ready to deploy your Angular application to a remote server, you have various options for deployment.

最簡單的部署選項

Simple deployment options

在完整部署應用之前,你可以先臨時用一種技術來測試流程、建構配置和部署行為。

Before fully deploying your application, you can test the process, build configuration, and deployed behavior by using one of these interim techniques.

從磁碟建構和提供服務

Building and serving from disk

在開發過程中,你通常會使用 ng serve 命令來藉助 webpack-dev-server 在本地記憶體中建構、監控和提供服務。但是,當你打算部署它時,就必須使用 ng build 命令來建構應用並在其它地方部署這些建構成果。

During development, you typically use the ng serve command to build, watch, and serve the application from local memory, using webpack-dev-server. When you are ready to deploy, however, you must use the ng build command to build the application and deploy the build artifacts elsewhere.

ng buildng serve 在建構專案之前都會清除輸出資料夾,但只有 ng build 命令會把產生的建構成果寫入輸出輸出資料夾中。

Both ng build and ng serve clear the output folder before they build the project, but only the ng build command writes the generated build artifacts to the output folder.

預設情況下,輸出目錄是 dist/project-name/。要輸出到其它資料夾,就要修改 angular.json 中的 outputPath

The output folder is dist/project-name/ by default. To output to a different folder, change the outputPath in angular.json.

當開發臨近收尾時,讓本地 Web 伺服器使用輸出資料夾中的內容提供服務可以讓你更好地瞭解當應用部署到遠端伺服器時的行為。你需要用兩個終端才能體驗到即時重新整理的特性。

As you near the end of the development process, serving the contents of your output folder from a local web server can give you a better idea of how your application will behave when it is deployed to a remote server. You will need two terminals to get the live-reload experience.

  • 在第一個終端上,在監控(watch)模式下執行 ng build 命令把該應用編譯進 dist 資料夾。

    On the first terminal, run the ng build command in watch mode to compile the application to the dist folder.

          
          ng build --watch
        

    ng serve 命令一樣,當原始檔發生變化時,就會重新產生輸出檔案。

    Like the ng serve command, this regenerates output files when source files change.

  • 在第二個終端上,安裝一個 Web 伺服器(比如 lite-server ),然後使用輸出資料夾中的內容執行它。例如:

    On the second terminal, install a web server (such as lite-server), and run it against the output folder. For example:

          
          lite-server --baseDir="dist/project-name"
        

    每當輸出了新檔案時,伺服器就會自動重新整理你的瀏覽器。

    The server will automatically reload your browser when new files are output.

該方法只能用於開發和測試,在部署應用時,它不受支援,也不是安全的方式。

This method is for development and testing only, and is not a supported or secure way of deploying an application.

使用 CLI 進行自動部署

Automatic deployment with the CLI

Angular CLI 命令 ng deploy(在版本 8.3.0 中引入)執行與你的專案關聯的 deploy CLI 建構器。有許多第三方建構器實現了到不同平臺的部署功能。你可以透過執行 ng add [package name] 把它們中的任何一個新增到專案中。

The Angular CLI command ng deploy (introduced in version 8.3.0) executes the deploy CLI builder associated with your project. A number of third-party builders implement deployment capabilities to different platforms. You can add any of them to your project by running ng add [package name].

新增具有部署功能的程式套件時,它將為所選專案自動更新自動更新工作區配置(angular.json 檔案)中的 deploy 部分。然後,你就可以使用 ng deploy 命令來部署該專案了。

When you add a package with deployment capability, it'll automatically update your workspace configuration (angular.json file) with a deploy section for the selected project. You can then use the ng deploy command to deploy that project.

例如,以下命令將專案自動部署到 Firebase。

For example, the following command automatically deploys a project to Firebase.

      
      ng add @angular/fire
ng deploy
    

該命令是互動式的。在這種情況下,你必須擁有或建立 Firebase 帳戶,並使用該帳戶進行身份驗證。該命令提示你選擇要部署的 Firebase 專案。

The command is interactive. In this case, you must have or create a Firebase account, and authenticate using that account. The command prompts you to select a Firebase project for deployment

該命令會建構你的應用,並將生產環境的資產檔案上傳到 Firebase。

The command builds your application and uploads the production assets to Firebase.

在下表中,你可以找到實現了到不同平臺部署功能的軟體套件列表。每個軟體套件的 deploy 命令可能需要不同的命令列選項。你可以透過以下與套件名稱相關的連結來閱讀更多內容:

In the table below, you can find a list of packages which implement deployment functionality to different platforms. The deploy command for each package may require different command line options. You can read more by following the links associated with the package names below:

部署到

Deployment to

NPM 套件

Package

Firebase hosting@angular/fire
Azure@azure/ng-deploy
Now@zeit/ng-deploy
Netlify@netlify-builder/deploy
GitHub pagesangular-cli-ghpages
NPMngx-deploy-npm
Amazon Cloud S3@jefiozie/ngx-aws-deploy

如果要部署到自己管理的伺服器上,或者缺少針對你喜歡的雲平臺的建構器,則可以建立支援你使用 ng deploy 命令的建構器,或者通讀本指南以瞭解如何手動部署應用程式。

If you're deploying to a self-managed server or there's no builder for your favorite cloud platform, you can either create a builder that allows you to use the ng deploy command, or read through this guide to learn how to manually deploy your application.

最簡化的部署方式

Basic deployment to a remote server

最簡化的部署方式就是為開發環境建構,並把其輸出複製到 Web 伺服器上。

For the simplest deployment, create a production build and copy the output directory to a web server.

  1. 使用開發環境進行建構

    Start with the production build:

          
          ng build
        
  2. 把輸出目錄(預設為 dist/)下的每個檔案都複製到到伺服器上的某個目錄下。

    Copy everything within the output folder (dist/project-name/ by default) to a folder on the server.

  3. 配置伺服器,讓缺失的檔案都重新導向到 index.html 上。 欲知詳情,參閱稍後的伺服器端重新導向部分。

    Configure the server to redirect requests for missing files to index.html. Learn more about server-side redirects below.

這是對應用進行生產環境部署的最簡方式。

This is the simplest production-ready deployment of your application.

部署到 GitHub Pages

Deploy to GitHub Pages

要將 Angular 應用程式部署到 GitHub Pages,請遵循以下步驟:

To deploy your Angular application to GitHub Pages, complete the following steps:

  1. 為你的專案建立一個 GitHub Pages 儲存庫

    Create a GitHub repository for your project.

  2. 透過新增指定你在上一步中建立的 GitHub 儲存函式庫的遠端地址,來在本地專案中配置 git。建立儲存函式庫時,GitHub 已提供了這些命令,以便你可以在命令提示符下複製和貼上它們。儘管 GitHub 會為你填上某些特定於專案的設定,但這些命令應該類似於以下形式:

    Configure git in your local project by adding a remote that specifies the GitHub repository you created in previous step. GitHub provides these commands when you create the repository so that you can copy and paste them at your command prompt. The commands should be similar to the following, though GitHub fills in your project-specific settings for you:

          
          git remote add origin https://github.com/your-username/your-project-name.git
    git branch -M main
    git push -u origin main
        

    當你從 GitHub 貼上這些命令時,它們會自動執行。

    When you paste these commands from GitHub, they run automatically.

  3. 建立並簽出一個名為 gh-pagesgit 分支。

    Create and check out a git branch named gh-pages.

          
          git checkout -b gh-pages
        
  4. 藉助 Angular CLI 命令 ng build和以下選項,使用 Github 專案名稱建構應用。這裡的 your_project_name 是你在步驟 1 中為 GitHub 儲存函式庫提供的專案的名稱。

    Build your project using the Github project name, with the Angular CLI command ng buildand the following options, where your_project_name is the name of the project that you gave the GitHub repository in step 1.

    確保在專案名稱的兩邊都包含有斜槓,如 /your_project_name/ 的斜槓。

    Be sure to include the slashes on either side of your project name as in /your_project_name/.

          
          ng build --output-path docs --base-href /your_project_name/
        
  5. 當建構完成時,把 docs/index.html 複製為 docs/404.html

    When the build is complete, make a copy of docs/index.html and name it docs/404.html.

  6. 提交你的更改,並推送。

    Commit your changes and push.

  7. 在 GitHub 的專案頁中,把該專案配置為從 docs 目錄下發布

    On the GitHub project page, go to Settings and scroll down to the GitHub Pages section to configure the site to publish from the docs folder.

  8. 單擊儲存。

    Click Save.

  9. 單擊 GitHub Pages 區頂部的 “GitHub Pages” 連結,以檢視已部署的應用程式。連結的格式為 https://<user_name>.github.io/<project_name>/

    Click on the GitHub Pages link at the top of the GitHub Pages section to see your deployed application. The format of the link is https://<user_name>.github.io/<project_name>/.

參閱 angular-cli-ghpages,這個套件用到了全部這些特性,還提供了一些額外功能。

Check out angular-cli-ghpages, a full featured package that does all this for you and has extra functionality.

伺服器端配置

Server configuration

這一節涵蓋了你可能對伺服器或準備部署到伺服器的檔案要做的那些修改。

This section covers changes you may have to make to the server or to files deployed on the server.

帶路由的應用必須以 index.html 作為後備頁面

Routed apps must fallback to index.html

Angular 應用很適合用簡單的靜態 HTML 伺服器提供服務。 你不需要伺服器端引擎來動態合成應用頁面,因為 Angular 會在客戶端完成這件事。

Angular applications are perfect candidates for serving with a simple static HTML server. You don't need a server-side engine to dynamically compose application pages because Angular does that on the client-side.

如果該應用使用 Angular 路由器,你就必須配置伺服器,讓它對不存在的檔案返回應用的宿主頁(index.html)。

If the application uses the Angular router, you must configure the server to return the application's host page (index.html) when asked for a file that it does not have.

帶路由的應用應該支援“深連結”。 所謂深連結就是指一個 URL,它用於指定到應用內某個元件的路徑。 比如,http://www.mysite.com/heroes/42 就是一個到英雄詳情頁面的深連結,用於顯示 id: 42 的英雄。

A routed application should support "deep links". A deep link is a URL that specifies a path to a component inside the application. For example, http://www.mysite.com/heroes/42 is a deep link to the hero detail page that displays the hero with id: 42.

當用戶從執行中的客戶端應用導航到這個 URL 時,這沒問題。 Angular 路由器會攔截這個 URL,並且把它路由到正確的頁面。

There is no issue when the user navigates to that URL from within a running client. The Angular router interprets the URL and routes to that page and hero.

但是,當從郵件中點選連結或在瀏覽器位址列中輸入它或僅僅在英雄詳情頁重新整理下瀏覽器時,所有這些操作都是由瀏覽器本身處理的,在應用的控制範圍之外。 瀏覽器會直接向伺服器請求那個 URL,路由器沒機會插手。

But clicking a link in an email, entering it in the browser address bar, or merely refreshing the browser while on the hero detail page — all of these actions are handled by the browser itself, outside the running application. The browser makes a direct request to the server for that URL, bypassing the router.

靜態伺服器會在收到對 http://www.mysite.com/ 的請求時返回 index.html,但是會拒絕對 http://www.mysite.com/heroes/42 的請求, 並返回一個 404 - Not Found 錯誤,除非,它被配置成了返回 index.html

A static server routinely returns index.html when it receives a request for http://www.mysite.com/. But it rejects http://www.mysite.com/heroes/42 and returns a 404 - Not Found error unless it is configured to return index.html instead.

後備頁面配置範例

Fallback configuration examples

沒有一種配置可以適用於所有伺服器。 後面這些部分會描述對常見伺服器的配置方式。 這個列表雖然不夠詳盡,但可以為你提供一個良好的起點。

There is no single configuration that works for every server. The following sections describe configurations for some of the most popular servers. The list is by no means exhaustive, but should provide you with a good starting point.

  • Apache:在 .htaccess 檔案中新增一個重寫規則, 程式碼如下(出處):

    Apache: add a rewrite rule to the .htaccess file as shown (https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/):

          
          RewriteEngine On
    # If an existing asset or directory is requested go to it as it is
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
    RewriteRule ^ - [L]
    # If the requested resource doesn't exist, use index.html RewriteRule ^ /index.html
  • NGinx:使用 try_files 指向 index.html,詳細描述見Web 應用的前端控制器模式

    Nginx: use try_files, as described in Front Controller Pattern Web Apps, modified to serve index.html:

          
          try_files $uri $uri/ /index.html;
        
  • Ruby:使用 sinatra 和用來配置伺服器的基礎 Ruby 檔案 server.rb 建立一個 Ruby 伺服器:

    Ruby: create a Ruby server using (sinatra) with a basic Ruby file that configures the server server.rb:

          
          require 'sinatra'
    
    # Folder structure
    
    # .
    
    # -- server.rb
    
    # -- public
    
    #    |-- project-name
    #        |-- index.html
    
    get '/' do
        folderDir = settings.public_folder + '/project-name'  # ng build output folder
        send_file File.join(folderDir, 'index.html')
    end
        
  • IIS:往 web.config 中新增一條重寫規則,類似於這裡

    IIS: add a rewrite rule to web.config, similar to the one shown here:

          
          <system.webServer>
      <rewrite>
        <rules>
          <rule name="Angular Routes" stopProcessing="true">
            <match url=".*" />
            <conditions logicalGrouping="MatchAll">
              <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
              <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
            </conditions>
            <action type="Rewrite" url="/index.html" />
          </rule>
        </rules>
      </rewrite>
    </system.webServer>
        
  • GitHub 頁面服務:你沒辦法直接配置 Github 的頁面服務,但可以新增一個 404 頁,只要把 index.html 複製到 404.html 就可以了。 它仍然會給出一個 404 響應,但是瀏覽器將會正確處理該頁,並正常載入該應用。 使用在主分支的 docs/ 下啟動服務建立一個 .nojekyll 檔案也是一個好辦法。

    GitHub Pages: you can't directly configure the GitHub Pages server, but you can add a 404 page. Copy index.html into 404.html. It will still be served as the 404 response, but the browser will process that page and load the application properly. It's also a good idea to serve from docs/ on master and to create a .nojekyll file

  • Firebase 託管服務:新增一條重寫規則

    Firebase hosting: add a rewrite rule.

          
          "rewrites": [ {
      "source": "**",
      "destination": "/index.html"
    } ]
        

請求來自另一個伺服器的服務(CORS)

Requesting services from a different server (CORS)

Angular 開發者在向與該應用的宿主伺服器不同域的伺服器發起請求時,可能會遇到一種跨域資源共享(CORS)錯誤。 瀏覽器會阻止該請求,除非得到那臺伺服器的明確許可。

Angular developers may encounter a cross-origin resource sharing error when making a service request (typically a data service request) to a server other than the application's own host server. Browsers forbid such requests unless the server permits them explicitly.

客戶端應用對這種錯誤無能為力。 伺服器必須配置成可以接受來自該應用的請求。 要了解如何對特定的伺服器開啟 CORS,參閱enable-cors.org

There isn't anything the client application can do about these errors. The server must be configured to accept the application's requests. Read about how to enable CORS for specific servers at enable-cors.org.

為生產環境優化

Production optimizations

production 配置項指定如下優化特性。

The production configuration engages the following build optimization features.

  • 預先(AOT)編譯:預編譯 Angular 的元件範本。

    Ahead-of-Time (AOT) Compilation: pre-compiles Angular component templates.

  • 生產模式:部署到啟用了生產模式的生產環境。

    Production mode: deploys the production environment which enables production mode.

  • 打包:把你的多個應用於函式庫檔案拼接到少量包(bundle)中。

    Bundling: concatenates your many application and library files into a few bundles.

  • 最小化:刪除多餘的空格、註釋和可選令牌。

    Minification: removes excess whitespace, comments, and optional tokens.

  • 混淆/醜化:重寫程式碼,使用簡短的、不容易理解的變數名和函式名。

    Uglification: rewrites code to use short, cryptic variable and function names.

  • 消除死程式碼:刪除未參考過的模組和很多未用到的程式碼。

    Dead code elimination: removes unreferenced modules and much unused code.

要了解關於 CLI 建構選項及其作用的更多知識,參閱 ng build

See ng buildfor more about CLI build options and what they do.

啟用生產模式

Enable runtime production mode

除了建構期優化之外,Angular 還支援執行期生產模式。Angular 應用預設執行在開發模式下,你可以在瀏覽器的控制檯中看到如下資訊:

In addition to build optimizations, Angular also has a runtime production mode. Angular applications run in development mode by default, as you can see by the following message on the browser console:

      
      Angular is running in development mode. Call enableProdMode() to enable production mode.

Angular 正執行在開發模式下。呼叫 enableProdMode()以啟用生產模式。
    

生產模式透過禁用僅供開發用的安全檢查和除錯工具(例如,expression-changed-after-checked 檢測)來提高應用程式效能。使用生產配置建構應用程式時會自動啟用 Angular 的執行時生產模式。

Production mode improves application performance by disabling development-only safety checks and debugging utilities, such as the expression-changed-after-checked detection. Building your application with the production configuration automatically enables Angular's runtime production mode.

延遲載入

Lazy loading

透過只載入應用啟動時絕對必須的那些模組,你可以極大縮短應用啟動的時間。

You can dramatically reduce launch time by only loading the application modules that absolutely must be present when the application starts.

可以配置 Angular 的路由器,來推遲所有其它模組(及其相關程式碼)的載入時機,方法有一直等到應用啟動完畢,或者當用到時才按需延遲載入

Configure the Angular Router to defer loading of all other modules (and their associated code), either by waiting until the app has launched or by lazy loading them on demand.

不要急性(eagerly)匯入來自延遲載入模組中的任何東西
Don't eagerly import something from a lazy-loaded module

如果要延遲載入某個模組,就要小心別在應用啟動時要急性載入的模組(比如根模組 AppModule)中匯入它。 如果那麼做,該模組就會立刻載入起來。

If you mean to lazy-load a module, be careful not to import it in a file that's eagerly loaded when the application starts (such as the root AppModule). If you do that, the module will be loaded immediately.

配置打包方式時必須考慮延遲載入。 因為預設情況下延遲載入的模組沒有在 JavaScript 中匯入過,因此打包器預設會排除它們。 打包器不認識路由器配置,也就不能為延遲載入的模組建立獨立的套件。 你必須手動建立這些套件。

The bundling configuration must take lazy loading into consideration. Because lazy-loaded modules aren't imported in JavaScript, bundlers exclude them by default. Bundlers don't know about the router configuration and can't create separate bundles for lazy-loaded modules. You would have to create these bundles manually.

CLI 會執行 Angular Ahead-of-Time Webpack 外掛,它會自動識別出延遲載入的 NgModules,並為它們建立獨立的套件。

The CLI runs the Angular Ahead-of-Time Webpack Plugin which automatically recognizes lazy-loaded NgModules and creates separate bundles for them.

測量效能

Measure performance

如果你對哪些東西拖慢了應用有更加清晰、精確的瞭解,就可以更好地決定優化什麼以及如何優化。 慢的原因可能和你所想的不一樣。 你可能花費了大量的時間和金錢來優化一些實際上無關緊要的東西,甚至可能讓應用變得更慢。 你應該測量應用在執行環境中的實際行為,這才是最重要的。

You can make better decisions about what to optimize and how when you have a clear and accurate understanding of what's making the application slow. The cause may not be what you think it is. You can waste a lot of time and money optimizing something that has no tangible benefit or even makes the application slower. You should measure the application's actual behavior when running in the environments that are important to you.

Chrome DevTools 的網路和效能頁是你開始學習如何測量效能的好地方。

The Chrome DevTools Network Performance page is a good place to start learning about measuring performance.

WebPageTest工具是另一個不錯的選擇,它還能幫你驗證這次部署是否成功。

The WebPageTest tool is another good choice that can also help verify that your deployment was successful.

檢查發佈套件

Inspect the bundles

source-map-explorer 工具可以幫你在生產環境建構之後探查 JavaScript 套件。

The source-map-explorer tool is a great way to inspect the generated JavaScript bundles after a production build.

安裝 source-map-explorer

Install source-map-explorer:

      
      npm install source-map-explorer --save-dev
    

為生產環境建構應用,包括原始碼對映表(source map)

Build your application for production including the source maps

      
      ng build --source-map
    

dist/ 目錄下列出產生的套件。

List the generated bundles in the dist/project-name/ folder.

      
      ls dist/project-name/*.js
    

執行瀏覽器來產生其中一個套件的圖形化表示。 下面的例子展示了 main 套件的圖表。

Run the explorer to generate a graphical representation of one of the bundles. The following example displays the graph for the main bundle.

      
      node_modules/.bin/source-map-explorer dist/project-name/main*
    

source-map-explorer 會分析與套件一起產生的 source map,並畫出所有依賴的地圖,精確展示哪些類別包含在哪個套件中。

The source-map-explorer analyzes the source map generated with the bundle and draws a map of all dependencies, showing exactly which classes are included in the bundle.

下面是範例應用 cli-quickstartmain 套件的輸出。

Here's the output for the main bundle of an example application called cli-quickstart.

base 標籤

The base tag

HTML 的 <base href="..."/> 標籤指定了用於解析靜態檔案(如圖片、指令碼和樣式表)相對地址的基地址。 比如,對於 <base href="/my/app/">,瀏覽器就會把 some/place/foo.jpg 這樣的 URL 解析成到 my/app/some/place/foo.jpg 的請求。 在導航期間,Angular 路由器使用 base href 作為到元件範本檔案和模組檔案的基地址。

The HTML <base href="..."/> specifies a base path for resolving relative URLs to assets such as images, scripts, and style sheets. For example, given the <base href="/my/app/">, the browser resolves a URL such as some/place/foo.jpg into a server request for my/app/some/place/foo.jpg. During navigation, the Angular router uses the base href as the base path to component, template, and module files.

另一種方式參閱 APP_BASE_HREF

See also the APP_BASE_HREF alternative.

在開發期間,你通常會在存有 index.html 的目錄下啟動開發伺服器。 那就是根目錄,你要在 index.html 的頂部附近新增 <base href="/">,因為 / 就是該應用的根路徑。

In development, you typically start the server in the folder that holds index.html. That's the root folder and you'd add <base href="/"> near the top of index.html because / is the root of the application.

但是在共享或生產伺服器上,你可能會在子目錄下啟動伺服器。 比如,當前應用的載入地址可能類似於 http://www.mysite.com/my/app/,這裡的子目錄就是 my/app/。所以你就要往伺服器端版本的 index.html 中新增 <base href="/my/app/">

But on the shared or production server, you might serve the application from a subfolder. For example, when the URL to load the application is something like http://www.mysite.com/my/app/, the subfolder is my/app/ and you should add <base href="/my/app/"> to the server version of the index.html.

這裡如果不配置 base 標籤,應用就會失敗,並在瀏覽器的控制檯中為缺失的檔案顯示一個 404 - Not Found 錯誤。看看它試圖從哪裡去查詢那些檔案,並據此調整 base 標籤。

When the base tag is mis-configured, the application fails to load and the browser console displays 404 - Not Found errors for the missing files. Look at where it tried to find those files and adjust the base tag appropriately.

差異化載入

Differential Loading

在建構 Web 應用時,你肯定想確保你的應用與大多數瀏覽器相容。JavaScript 在不斷髮展,新功能不斷推出,不是所有瀏覽器都能以同樣的進度實現這些新功能。

When building web applications, you want to make sure your application is compatible with the majority of browsers. Even as JavaScript continues to evolve, with new features being introduced, not all browsers are updated with support for these new features at the same pace.

你在開發過程中使用 TypeScript 編寫的程式碼會被編譯並打包成 ES2015,這種 JavaScript 語法相容大多數瀏覽器。 所有現代瀏覽器都支援 ES2015 和更新的版本,但是大多數情況下,你仍然要讓使用者能從不支援它的瀏覽器中訪問你的應用。 當以老式瀏覽器為目標時,Polyfill指令碼(polyfills)可以提供一些老式瀏覽器中不存在的功能,從而抹平這種差距。

The code you write in development using TypeScript is compiled and bundled into ES2015, the JavaScript syntax that is compatible with most browsers. All modern browsers support ES2015 and beyond, but in most cases, you still have to account for users accessing your application from a browser that doesn't. When targeting older browsers, polyfills can bridge the gap by providing functionality that doesn't exist in the older versions of JavaScript supported by those browsers.

為了最大限度地提高相容性,你可以發佈一個包含所有已編譯程式碼的發佈套件(bundle),以及所有可能會用到的Polyfill指令碼。使用者如果在支援大量最新 JavaScript 特性的現代瀏覽器中使用此應用,就不應該為這些他們用不到的套件帶來的額外體積付出代價。差異化載入可以幫你解決這個問題。Angular CLI 8 及更高版本就支援它。

To maximize compatibility, you could ship a single bundle that includes all your compiled code, plus any polyfills that may be needed. Users with modern browsers, however, shouldn't have to pay the price of increased bundle size that comes with polyfills they don't need. Differential loading, which is supported in Angular CLI version 8 and higher, can help solve this problem.

差異化載入是一種策略,它能讓你的應用支援多種瀏覽器,但是只載入當前瀏覽器必須用到的程式碼。 當啟用了差異化載入時,CLI 會構建出兩個單獨的套件,作為你要發佈的應用的一部分。

Differential loading is a strategy that allows your web application to support multiple browsers, but only load the necessary code that the browser needs. When differential loading is enabled the CLI builds two separate bundles as part of your deployed application.

  • 第一個套件是使用現代的 ES2015 語法,它能發揮現代瀏覽器內建支援的優勢,發佈更少的Polyfill指令碼,因此打包尺寸更小。

    The first bundle contains modern ES2015 syntax. This bundle takes advantage of built-in support in modern browsers, ships fewer polyfills, and results in a smaller bundle size.

  • 第二個套件使用老式的 ES5 語法,包含所有必要的Polyfill指令碼。第二個套件的尺寸更大,但是支援老式瀏覽器。

    The second bundle contains code in the old ES5 syntax, along with all necessary polyfills. This second bundle is larger, but supports older browsers.

差異化建構

Differential builds

使用 Angular CLI 建構過程進行部署時,可以選擇如何以及何時支援差異化載入。ng build CLI 命令會查詢瀏覽器配置和配置的建構目標,以確定是否需要支援舊版瀏覽器,以及該建構是否應產生用於差異化載入的必要捆綁套件。

When you deploy using the Angular CLI build process, you can choose how and when to support differential loading. The ng build CLI command queries the browser configuration and the configured build target to determine if support for legacy browsers is required, and whether the build should produce the necessary bundles used for differential loading.

會根據下列配置確定你的要求。

The following configurations determine your requirements.

  • 瀏覽器列表

    Browserslist

    browserslist 配置檔案包含在應用的專案結構中,它提供了本應用打算支援的最低瀏覽器版本。關於完整的配置選項,請參閱 Browserslist 規範

    The Browserslist configuration file is included in your application project structure and provides the minimum browsers your application supports. See the Browserslist spec for complete configuration options.

  • TypeScript 配置

    TypeScript configuration

    在 TypeScript 配置檔案中,compilerOptions 區的 target 選項會決定編譯後代碼的 ECMAScript 目標版本。現代瀏覽器原生支援 ES2015,而 ES5 則更常用於支援老式瀏覽器。

    In the TypeScript configuration file, the "target" option in the compilerOptions section determines the ECMAScript target version that the code is compiled to. Modern browsers support ES2015 natively, while ES5 is more commonly used to support legacy browsers.

當前僅在將 es2015 用作編譯目標時才支援差異化載入。當目標高於 es2015 時,建構過程將發出警告。

Differential loading is currently only supported when using es2015 as a compilation target. When used with targets higher than es2015, the build process emits a warning.

對於開發版本,由 ng build 產生的輸出更簡單且易於除錯,從而減小你對編譯程式碼的 sourcemaps 的依賴。

For a development build, the output produced by ng build is simpler and easier to debug, allowing you to rely less on sourcemaps of compiled code.

對於生產版本,你的配置將決定建立哪些捆綁軟體來部署你的應用程式。必要時,還會在建構過程中修改 index.html 檔案,以包括啟用差異化載入的指令碼標籤,如以下範例所示。

For a production build, your configuration determines which bundles are created for deployment of your application. When needed, the index.html file is also modified during the build process to include script tags that enable differential loading, as shown in the following example.

index.html
      
      <body>
  <app-root></app-root>
  <script src="runtime-es2015.js" type="module"></script>
  <script src="runtime-es5.js" nomodule></script>
  <script src="polyfills-es2015.js" type="module"></script>
  <script src="polyfills-es5.js" nomodule></script>
  <script src="styles-es2015.js" type="module"></script>
  <script src="styles-es5.js" nomodule></script>
  <script src="vendor-es2015.js" type="module"></script>
  <script src="vendor-es5.js" nomodule></script>
  <script src="main-es2015.js" type="module"></script>
  <script src="main-es5.js" nomodule></script>
</body>
    

每個 script 標籤都有一個 type="module"nomodule 屬性。原生支援 ES 模組的瀏覽器只會載入帶有該型別屬性的指令碼,而忽略那些帶有 nomodule 屬性的指令碼。而老式瀏覽器只會載入帶有 nomodule 屬性的指令碼,而忽略那些 type 為 module 的指令碼標籤。

Each script tag has a type="module" or nomodule attribute. Browsers with native support for ES modules only load the scripts with the module type attribute and ignore scripts with the nomodule attribute. Legacy browsers only load the scripts with the nomodule attribute, and ignore the script tags with the module type that load ES modules.

一些舊版瀏覽器仍會下載兩個捆綁套件,但只會根據上述屬性執行適當的指令碼。你可以在此處閱讀關於此問題的更多資訊

Some legacy browsers still download both bundles, but only execute the appropriate scripts based on the attributes mentioned above. You can read more on the issue here.

配置差異化載入

Configuring differential loading

要想在建構應用時包含差異化載入特性,你必須修改專案中的 Browserslist 和 TypeScript 配置檔案。

To include differential loading in your application builds, you must configure the Browserslist and TypeScript configuration files in your application project.

下面的例子展示了新建立的 Angular 應用的 browserlistrctsconfig.json 檔案。 在這份配置中,老式瀏覽器(比如 IE 9-11)都被忽略了,其編譯目標是 ES2015。

The following examples show a .browserslistrc and tsconfig.json file for a newly created Angular application. In this configuration, legacy browsers such as IE 9-11 are ignored, and the compilation target is ES2015.

.browserslistrc
      
      # This file is used by the build system to adjust CSS and JS output to support the specified browsers below.

# 建構系統使用此檔案來調整 CSS 和 JS 輸出,以支援下列指定的瀏覽器。

# For additional information regarding the format and rule options, please see:

# 有關格式和規則選項的其他資訊,請參見:

# https://github.com/browserslist/browserslist#queries

# For the full list of supported browsers by the Angular framework, please see:

# 有關 Angular 框架支援的瀏覽器的完整列表,請參見:

# https://angular.io/guide/browser-support

# You can see what browsers were selected by your queries by running:

# 你可以透過執行以下命令檢視你指定的查詢選擇了哪些瀏覽器:

#   npx browserslist

last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
    
tsconfig.json
      
      {
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "module": "esnext",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "importHelpers": true,
    "target": "es2015",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2018",
      "dom"
    ]
  }
}
    

要檢視瀏覽器的支援度,以決定哪些設定適合你要支援的瀏覽器,請參閱“ 瀏覽器列表相容性”頁面

To see which browsers are supported and determine which settings meet to your browser support requirements, see the Browserslist compatibility page.

Browserslist 配置允許你忽略不支援 ES2015 的瀏覽器。在這種情況下,將只產生一個版本。

The Browserslist configuration allows you to ignore browsers without ES2015 support. In this case, a single build is produced.

如果你的 Browserslist 配置包括對所有舊版瀏覽器的支援,則 TypeScript 配置中的建構目標將確定該建構是否將支援差異化載入。

If your Browserslist configuration includes support for any legacy browsers, the build target in the TypeScript configuration determines whether the build will support differential loading.

瀏覽器列表

Browserslist

ES 目標

ES target

建構結果

Build result

禁用 ES5 支援

ES5 support disabled

es2015

單一建構,不行可 ES5

Single build, ES5 not required

啟用 ES5 支援

ES5 support enabled

es5

單一建構,按需附帶只供 ES5 使用的Polyfill指令碼

Single build w/conditional polyfills for ES5 only

棄用 ES5 支援

ES5 support enabled

es2015

差異化載入 (按需附帶兩種建構需要的Polyfill指令碼)

Differential loading (two builds w/conditional polyfills)

舊版瀏覽器中的本地開發

Local development in older browsers

在 Angular CLI 10 或更高版本產生的應用專案中,預設是不啟用差異化載入的。 ng serveng testng e2e 命令只會產生一個 ES2015 版本,該版本無法在不支援該模組的舊版瀏覽器(例如 IE 11)中執行。

Differential loading is not enabled by default for application projects that were generated with Angular CLI 10 and above. The ng serve, ng test, and ng e2e commands, however, generate a single ES2015 build which cannot run in older browsers that don't support the modules, such as IE 11.

要保持差異化載入的好處,更好的選擇是為 ng serveng e2eng test 定義多個配置。

To maintain the benefits of differential loading, however, a better option is to define multiple configurations for ng serve, ng e2e, and ng test.

為 ES5 配置服務

Configuring serve for ES5

要讓 ng serve 做到這一點,就要在 tsconfig.app.json 後面建立一個新的檔案 tsconfig-es5.app.json,包含以下內容。

To do this for ng serve, create a new file, tsconfig-es5.app.json next to tsconfig.app.json with the following content.

      
      {
 "extends": "./tsconfig.app.json",
 "compilerOptions": {
     "target": "es5"
  }
}
    

angular.json 中,在 buildserve 下新增兩個新的配置節,其目標指向新的 TypeScript 配置。

In angular.json add two new configuration sections under the build and serve targets to point to the new TypeScript configuration.

      
      "build": {
  "builder": "@angular-devkit/build-angular:browser",
  "options": {
      ...
  },
  "configurations": {
    "production": {
        ...
    },
    "es5": {
      "tsConfig": "./tsconfig-es5.app.json"
    }
  }
},
"serve": {
  "builder": "@angular-devkit/build-angular:dev-server",
  "options": {
      ...
  },
  "configurations": {
    "production": {
     ...
    },
    "es5": {
      "browserTarget": "<app-name>:build:es5"
    }
  }
},
    

然後,你可以使用此配置執行 ng serve 命令。務必確保將 <app-name>(在 "<app-name>:build:es5" 中)替換為應用程式的實際名稱,因為它也會出現在 angular.jsonprojects 中。例如,如果你的應用程式名稱為 myAngularApp 則配置要變成 "browserTarget": "myAngularApp:build:es5"

You can then run the ng serve command with this configuration. Make sure to replace <app-name> (in "<app-name>:build:es5") with the actual name of the app, as it appears under projects in angular.json. For example, if your application name is myAngularApp the configuration will become "browserTarget": "myAngularApp:build:es5".

      
      ng serve --configuration es5
    

配置 test 命令

Configuring the test command

建立一個新的檔案,在 tsconfig.spec.json 後面 tsconfig-es5.spec.json,包含以下內容。

Create a new file, tsconfig-es5.spec.json next to tsconfig.spec.json with the following content.

      
      {
 "extends": "./tsconfig.spec.json",
 "compilerOptions": {
     "target": "es5"
  }
}
    
      
      "test": {
  "builder": "@angular-devkit/build-angular:karma",
  "options": {
      ...
  },
  "configurations": {
    "es5": {
      "tsConfig": "./tsconfig-es5.spec.json"
    }
  }
},
    

然後,你可以使用此配置執行測試了

You can then run the tests with this configuration

      
      ng test --configuration es5