Làm thế nào để giảm kích thước bó prod?


135

Tôi có một ứng dụng đơn giản, khởi tạo bởi angular-cli.

Nó hiển thị một số trang liên quan đến 3 tuyến đường. Tôi có 3 thành phần. Trên một trong những trang này, tôi sử dụng lodashvà các mô-đun HTTP Angular 2 để lấy một số dữ liệu (sử dụng RxJS Observables mapsubscribe). Tôi hiển thị các yếu tố này bằng cách sử dụng đơn giản *ngFor.

Nhưng, mặc dù thực tế ứng dụng của tôi rất đơn giản, tôi nhận được một gói và bản đồ rất lớn (theo ý kiến ​​của tôi). Tôi không nói về các phiên bản gzip nhưng kích thước trước khi gzipping. Câu hỏi này chỉ là một cuộc điều tra khuyến nghị chung.

Một số kết quả xét nghiệm:

ng xây dựng

Hash: 8efac7d6208adb8641c1 Thời gian: 10129ms chunk {0} main.bundle.js, main.bundle.map (chính) 18,7 kB {3} [ban đầu] [kết xuất]

chunk

chunk {2} scripts.bundle.js, scripts.bundle.map (scripts) 128 kB {4} [ban đầu] [kết xuất]

chunk {3} eller.bundle.js, eller.bundle.map (nhà cung cấp) 3,96 MB [ban đầu] [kết xuất]

chunk {4} inline.bundle.js, inline.bundle.map (nội tuyến) 0 byte [entry] [render]

Chờ đã: Gói gói nhà cung cấp 10Mb cho một ứng dụng đơn giản như vậy?

ng xây dựng - sản phẩm

Hash: 09a5f095e33b2980e7cc Thời gian: 23455ms chunk {0} main.6273b0f04a07a1c2ad6c.bundle.js, main.6273b0f04a07a1c2ad6c.bundle.map (chính)

chunk {1} style.bfdaa4d8a4eb2d0cb019.bundle.css, style.bfdaa4d8a4eb2d0cb019.bundle.map, Styles.bfdaa4d8a4eb2d0cbb.

chunk {2} scripts.c5b720a078e5464ec211.bundle.js, scripts.c5b720a078e5464ec211.bundle.map (script) 128 kB {4} [ban đầu] [kết xuất]

chunk {3} nhà cung cấp.07af2467307e17d85438.bundle.js, nhà cung cấp.07af2467307e17d85438.bundle.map (nhà cung cấp) 3,96 MB [ban đầu] [kết xuất]

chunk {4} inline.a345391d459797f81820.bundle.js, inline.a345391d459797f81820.bundle.map (nội tuyến) 0 byte [entry] [render]

Đợi một lần nữa: kích thước gói nhà cung cấp tương tự như vậy cho prod?

ng build --prod --aot

Hash: 517e4425ff872bbe3e5b Thời gian: 22856ms chunk {0} main.95eadabace554e3c2b43.bundle.js, main.95eadabace554e3c2b43.bundle.map (chính) 130 kB {3]

chunk {1} style.e53a388ae1dd2b7f5434.bundle.css, style.e53a388ae1dd2b7f5434.bundle.map, Styles.e53a388ae1dd2b7f5434.bundle.map [4]

chunk {2} scripts.e5c2c90547f3168a7564.bundle.js, scripts.e5c2c90547f3168a7564.bundle.map (scripts) 128 kB {4} [ban đầu] [kết xuất]

chunk {3} nhà cung cấp.41a6c1f57136df286f14.bundle.js, nhà cung cấp.41a6c1f57136df286f14.bundle.map (nhà cung cấp) 2.75 MB [ban đầu] [kết xuất]

chunk {4} inline.97c0403c57a46c6a7920.bundle.js, inline.97c0403c57a46c6a7920.bundle.map (nội tuyến) 0 byte [entry] [render]

ng build --aot

Hash: 040cc91df4df5ffc3c3f Thời gian: 11011ms chunk {0} main.bundle.js, main.bundle.map (main) 130 kB {3} [ban đầu] [kết xuất]

chunk

chunk {2} scripts.bundle.js, scripts.bundle.map (scripts) 128 kB {4} [ban đầu] [kết xuất]

chunk {3} eller.bundle.js, eller.bundle.map (nhà cung cấp) 2,75 MB [ban đầu] [kết xuất]

chunk {4} inline.bundle.js, inline.bundle.map (nội tuyến) 0 byte [entry] [render]

Vì vậy, một vài câu hỏi để triển khai ứng dụng của tôi trên prod:

  • Tại sao các gói nhà cung cấp rất lớn?
  • Cây lắc có được sử dụng đúng cách angular-clikhông?
  • Làm thế nào để cải thiện kích thước bó này?
  • Là các tập tin .map cần thiết?
  • Là các tính năng kiểm tra bao gồm trong gói? Tôi không cần chúng trong prod.
  • Câu hỏi chung: các công cụ được đề xuất để đóng gói cho prod là gì? Có lẽ angular-cli(sử dụng Webpack trong nền) không phải là lựa chọn tốt nhất? Chúng ta có thể làm tốt hơn không?

Tôi đã tìm kiếm nhiều cuộc thảo luận về Stack Overflow, nhưng tôi không tìm thấy bất kỳ câu hỏi chung chung nào.


Để tìm hiểu thêm về tối ưu hóa ứng dụng góc 2, hãy xem điều này: github.com/mgechev/angular-performance-checklist#int
sinhtion

1
Nhưng tôi không nghĩ rằng chúng ta nên quan tâm rằng nhiều, góc cạnh sẽ phát triển và mọi thứ sẽ được thực hiện ngày càng tốt hơn. Nếu bạn cần một số tính năng mà angular-cli không có, chỉ cần gửi một vấn đề trong repo của họ: github.com/angular/angular-cli
Timathon

Mặc dù tôi nghĩ rằng @Timathon đúng theo một số cách, nếu bất cứ ai đang cố gắng triển khai Angular2 vào sản xuất, họ nên quan tâm đến kích thước gói vì điều này ảnh hưởng trực tiếp đến hiệu suất ứng dụng. Danh sách kiểm tra hiệu suất góc là một nguồn tuyệt vời để xem những gì có thể được cải thiện. nhóm góc đang làm việc để giảm kích thước bó. Vui mừng khi thấy nó đi đâu!
Jack Clancy

Câu trả lời:


72

Cập nhật tháng 2 năm 2020

Vì câu trả lời này có rất nhiều lực kéo, tôi nghĩ rằng tốt nhất nên cập nhật nó với các tối ưu hóa Angular mới hơn:

  1. Như một người trả lời khác đã nói, ng build --prod --build-optimizerlà một lựa chọn tốt cho những người sử dụng ít hơn Angular v5. Đối với các phiên bản mới hơn, điều này được thực hiện theo mặc định vớing build --prod
  2. Một tùy chọn khác là sử dụng mô-đun chunking / tải lười biếng để phân chia ứng dụng của bạn thành các phần nhỏ hơn
  3. Công cụ kết xuất Ivy được mặc định trong Angular 9, nó cung cấp kích thước gói tốt hơn
  4. Hãy chắc chắn rằng deps bên thứ 3 của bạn có thể rung cây. Nếu bạn chưa sử dụng Rxjs v6, bạn nên làm vậy.
  5. Nếu vẫn thất bại, hãy sử dụng một công cụ như phân tích gói webpack để xem điều gì gây ra sự phình to trong các mô-đun của bạn
  6. Kiểm tra xem các tập tin của bạn đã được nén

Một số tuyên bố rằng sử dụng trình biên dịch AOT có thể giảm kích thước gói của nhà cung cấp xuống 250kb. Tuy nhiên, trong ví dụ của BlackHoleGal Wax, anh ta sử dụng trình biên dịch AOT và vẫn còn lại với kích thước gói nhà cung cấp là 2,75 MB ng build --prod --aot, lớn hơn gấp 10 lần so với 250kb. Điều này không nằm ngoài định mức cho các ứng dụng angular2, ngay cả khi bạn đang sử dụng v4.0. 2,75 MB vẫn còn quá lớn đối với bất kỳ ai thực sự quan tâm đến hiệu suất, đặc biệt là trên thiết bị di động.

Có một vài điều bạn có thể làm để giúp hiệu suất của ứng dụng của bạn:

1) AOT & Tree Shakes (angular-cli thực hiện điều này ra khỏi hộp). Với Angular 9 AOT theo mặc định trên môi trường prod và dev.

2) Sử dụng kết xuất phía máy chủ Angular Universal AKA (không phải trong cli)

3) Công nhân web (một lần nữa, không phải trong cli, nhưng một tính năng rất được yêu cầu)
xem: https://github.com/angular/angular-cli/issues/2305

4) Nhân viên phục vụ
xem: https://github.com/angular/angular-cli/issues/4006

Bạn có thể không cần tất cả những thứ này trong một ứng dụng, nhưng đây là một số tùy chọn hiện có để tối ưu hóa hiệu suất của Angular. Tôi tin / hy vọng Google nhận thức được những thiếu sót vượt trội về hiệu suất và kế hoạch cải thiện điều này trong tương lai.

Đây là một tài liệu tham khảo nói sâu hơn về một số khái niệm tôi đã đề cập ở trên:

https://medium.com/@areai51/the-4-stages-of-perf-tuning-for-your-angular2-app-922ce5c1b294


Dự án tối thiểu của tôi là 384kB, xem github.com/JCornat/min-angular Tôi chắc chắn có cách dễ dàng để tối ưu hóa nó, nhưng nó gần 250kB!
Jacques Cornat

2
@JacquesCornat có vẻ tốt! Nhưng ứng dụng của bạn chỉ có một thành phần duy nhất. Câu hỏi là làm thế nào để quản lý kích thước gói hoặc các ứng dụng lớn hơn. Thường thì AOT không giảm đủ kích cỡ bó và mọi người buộc phải nhìn theo cách khác để tối ưu hóa. Tôi đặc biệt khuyên mọi người nên kiểm tra webpack-bundle-analyzer. Một cách rất hữu ích / dễ dàng để xem những gì gây ra phình to
Jack Clancy

Thật không may, các tiện ích như sw-precachetừ chối xử lý các gói nhà cung cấp lớn hơn 2MB.

1
@JackClancy "Câu hỏi là làm thế nào để quản lý kích thước gói hoặc ứng dụng lớn hơn". Không có câu hỏi của ông là "làm thế nào để cải thiện kích thước bó này?" và anh ấy đang nói về ứng dụng tối thiểu của mình với 3 thành phần. Dù sao, nói về các gói lớn, sử dụng cấu hình AngularClass / angular-starter, giống như trong repo của tôi, kích thước gói của tôi cho các ứng dụng lớn đã tăng từ 8MB (4 MB không có tệp bản đồ) lên tới 580kB.
Jacques Cornat

1
Cảm ơn, bạn đã cứu tôi. --prod đã giảm kích thước ứng dụng từ 6Mb xuống còn 1.2Mb. Vẫn không hoàn hảo, nhưng chấp nhận vì nó chỉ dành cho máy tính để bàn.
Vyacheslav Tsivina

21

Sử dụng phiên bản cli góc mới nhất và sử dụng lệnh ng build --prod --build-Optimizer Nó chắc chắn sẽ giảm kích thước bản dựng cho prod env.

Đây là những gì trình tối ưu hóa xây dựng thực hiện dưới mui xe:

Trình tối ưu hóa xây dựng có hai công việc chính. Đầu tiên, chúng tôi có thể đánh dấu các phần trong ứng dụng của bạn là thuần túy, điều này giúp cải thiện độ rung của cây được cung cấp bởi các công cụ hiện có, loại bỏ các phần bổ sung trong ứng dụng của bạn không cần thiết.

Điều thứ hai trình tối ưu hóa xây dựng làm là loại bỏ các trình trang trí Angular khỏi mã thời gian chạy của ứng dụng của bạn. Trình trang trí được trình biên dịch sử dụng và không cần thiết trong thời gian chạy và có thể được gỡ bỏ. Mỗi công việc này làm giảm kích thước các gói JavaScript của bạn và tăng tốc độ khởi động ứng dụng cho người dùng của bạn.

Lưu ý : Một bản cập nhật cho Angular 5 trở lên, ng build --prodtự động thực hiện quy trình trên :)


1
Đối với góc 6 ngay bây giờ, nhà cung cấp vẫn còn 4 MB khi chỉ cài đặt góc / vật liệu và căn cứ hỏa lực
FindOutIslamNow

Đó là một vấn đề với góc / vật liệu, thậm chí tôi đã phải đối mặt với lỗi đó. Cây rung lắc không được thực hiện chính xác có lẽ là nguyên nhân gốc rễ. Với công cụ kết xuất mới IVY có lẽ nó sẽ được giải quyết.
Shubhendu đã trả lời

13

Lodash có thể đóng góp một đoạn mã lỗi cho gói của bạn tùy thuộc vào cách bạn nhập từ nó. Ví dụ:

// includes the entire package (very large)
import * as _ from 'lodash';

// depending on your buildchain, may still include the entire package
import { flatten } from 'lodash';

// imports only the code needed for `flatten`
import flatten from 'lodash-es/flatten'

Cá nhân tôi vẫn muốn dấu chân nhỏ hơn từ các chức năng tiện ích của tôi. Ví dụ, flattencó thể đóng góp tối đa 1.2Kcho gói của bạn, sau khi giảm thiểu. Vì vậy, tôi đã xây dựng một bộ sưu tập các hàm lodash đơn giản hóa. Tôi thực hiện các flattenđóng góp xung quanh 50 bytes. Bạn có thể kiểm tra nó ở đây để xem nó có phù hợp với bạn không: https://github.com/simontonsoftware/micro-dash


1
2 / Tôi đã thử các mẹo "loadash-es" từ nhận xét ở trên. Nó làm giảm kích thước gói của tôi là 0,08mb.
Stefdelec

Đó không phải là nhiều! Bạn vẫn có bất cứ điều gì khác nhập lodash theo cách cũ? Bạn sẽ không nhận được bất kỳ trợ giúp trừ khi mọi thứ được nhập theo cách mới.
Eric Simonton

Tôi nghĩ rằng tôi đã thay thế mọi thứ. Kích thước sẽ không thay đổi. Tôi đã đưa ra một mẹo khác dưới đây (điều gzip) thực sự giúp chúng tôi.
Stefdelec

Hấp dẫn. Bao nhiêu gói của bạn là / đã được đóng góp vào? (Ví dụ: sử dụng source-map-explorer.)
Eric Simonton

11

Thứ nhất, các gói nhà cung cấp rất lớn chỉ đơn giản vì Angular 2 phụ thuộc vào rất nhiều thư viện. Kích thước tối thiểu cho ứng dụng Angular 2 là khoảng 500KB (trong một số trường hợp, xem bài dưới cùng).
Cây lắc được sử dụng đúng cách angular-cli.
Đừng không bao gồm .maptác phẩm, bởi vì chỉ sử dụng để gỡ lỗi. Hơn nữa, nếu bạn sử dụng mô-đun thay thế nóng, hãy loại bỏ nó để làm nhẹ nhà cung cấp.

Để đóng gói cho sản xuất, tôi thường sử dụng Webpack (và angular-cli cũng dựa vào nó ), vì bạn thực sự có thể configure everythingtối ưu hóa hoặc gỡ lỗi.
Nếu bạn muốn sử dụng Webpack, tôi đồng ý rằng đây là một góc nhìn hơi khó, nhưng xem hướng dẫn trên mạng, bạn sẽ không thất vọng.
Khác, sử dụng angular-cli, mà có được công việc thực hiện rất tốt.

Sử dụng biên dịch trước thời gian là bắt buộc để tối ưu hóa các ứng dụng và thu nhỏ ứng dụng Angular 2 thành 250KB .

Đây là một repo tôi đã tạo ( github.com/JCornat/min-angular ) để kiểm tra kích thước bó góc tối thiểu và tôi thu được 384kB . Tôi chắc chắn có cách dễ dàng để tối ưu hóa nó.

Nói về các ứng dụng lớn, sử dụng cấu hình AngularClass / angular-starter , giống như trong repo ở trên, kích thước gói của tôi cho các ứng dụng lớn ( hơn 150 thành phần ) đã tăng từ 8MB (4 MB không có tệp bản đồ) lên tới 580kB .


Cấu hình angular-starter cụ thể nào giúp giảm kích thước bó? Có phải là webpack.config?
MartinJH

2
Có, đó là cấu hình webpack làm giảm kích thước gói.
Jacques Cornat

Cảm ơn đã làm rõ :)
MartinJH

8

Giải pháp sau đây giả sử bạn đang phục vụ dist / thư mục của mình bằng cách sử dụng nodejs. Vui lòng sử dụng các app.js sau ở cấp độ gốc

const express = require('express'),http = require('http'),path = require('path'),compression = require('compression');

const app = express();

app.use(express.static(path.join(__dirname, 'dist')));
app.use(compression()) //compressing dist folder 
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'dist/index.html'));
})

const port = process.env.PORT || '4201';
app.set('port', port);

const server = http.createServer(app);
server.listen(port, () => console.log('Running at port ' + port))

Hãy chắc chắn rằng bạn cài đặt các phụ thuộc;

npm install compression --save
npm install express --save;

Bây giờ xây dựng ứng dụng

ng build --prod --build-optimizer

Nếu bạn muốn nén thêm bản dựng, hãy giảm 300kb (khoảng) từ, sau đó làm theo quy trình dưới đây;

Tạo một thư mục được gọi vendorbên trong srcthư mục và bên trong thư mục nhà cung cấp tạo một tệp rxjs.ts và dán mã dưới đây vào đó;

export {Subject} from 'rxjs/Subject';
export {Observable} from 'rxjs/Observable';
export {Subscription} from 'rxjs/Subscription';

Và sau đó thêm follwing trong tsconfig.jsontệp trong ứng dụng angular-cli của bạn. Sau đó, trong compilerOptionsjson sau;

"paths": {
      "rxjs": [
        "./vendor/rxjs.ts"
      ]
    }

Điều này sẽ làm cho kích thước xây dựng của bạn quá nhỏ. Trong dự án của tôi, tôi đã giảm kích thước từ 11mb xuống còn 1mb. Hy vọng nó giúp


5

Một điều tôi muốn chia sẻ là làm thế nào các thư viện nhập khẩu tăng kích thước của dist. Tôi đã nhập gói angular2-khoảnh khắc, trong khi tôi có thể thực hiện tất cả định dạng thời gian ngày tôi yêu cầu bằng cách sử dụng DatePipe tiêu chuẩn được xuất từ ​​@ angular / common.

Với Angular2-Khoảnh khắc "angular2-moment": "^1.6.0",

chunk {0} polyfills.036982dc15bb5fc67cb8.bundle.js (polyfills) 191 kB {4} [ban đầu] [render] chunk {1} main.e7496551a26816427b68.bundle.js (chính) chunk {2} style.056656ed596d26ba0192.bundle.css (style) 69 byte {4} [ban đầu] [render] chunk {3} nhà cung cấp.62c2cfe0ca794a5006d1.bundle.js (nhà cung cấp) 3.84 MB [ban đầu] } inline.0b9c3de53405d705e757.bundle.js (nội tuyến) 0 byte [entry] [render]

Sau khi xóa Angular2-khoảnh khắc và sử dụng DatePipe thay thế

chunk {0} polyfills.036982dc15bb5fc67cb8.bundle.js (polyfills) 191 kB {4} [ban đầu] [render] chunk {1} main.f2b62721788695a4655c.bundle.js chunk {2} style.056656ed596d26ba0192.bundle.css (style) 69 byte {4} [ban đầu] [render] chunk {3} eller.e1de06303258c58c9d01.bundle.js (nhà cung cấp) 3.35 MB [ban đầu] } inline.3ae24861b3637391ba70.bundle.js (nội tuyến) 0 byte [entry] [render]

Lưu ý gói nhà cung cấp đã giảm một nửa Megabyte!

Điểm đáng để kiểm tra là các gói tiêu chuẩn góc có thể làm gì ngay cả khi bạn đã quen với lib bên ngoài.



1

Nếu bạn đã chạy ng build --prod- bạn hoàn toàn không nên có vendortập tin.

Nếu tôi chỉ chạy ng build- tôi nhận được các tệp này:

nhập mô tả hình ảnh ở đây

Tổng kích thước của thư mục là ~ 14MB. Chờ đợi! : D

Nhưng nếu tôi chạy ng build --prod- tôi nhận được các tệp này:

nhập mô tả hình ảnh ở đây

Tổng kích thước của thư mục là 584K.

Một và cùng một mã. Tôi đã kích hoạt Ivy trong cả hai trường hợp. Góc là 8.2.13.

Vì vậy - tôi đoán bạn đã không thêm --prodvào lệnh xây dựng của mình?


1

Nếu bạn đang sử dụng Angular 8+ và bạn muốn giảm kích thước của gói, bạn có thể sử dụng Ivy. Ivy là công cụ xem mặc định trong Angular 9, chỉ cần truy cập src / tsconfig.app.json và thêm tham số angularCompilerOptions, ví dụ:

{
  "extends": ...,
  "compilerOptions":...,
  "exclude": ...,

/* add this one */ 
  "angularCompilerOptions": {
    "enableIvy": true
  }
}

1

Điều này đã làm giảm kích thước trong trường hợp của tôi:

ng build --prod --build-optimizer --optimization.

Đối với Angular 5+ ng-build --prod thực hiện việc này theo mặc định. Kích thước sau khi chạy lệnh này giảm từ 1,7 MB xuống 1,2 MB, nhưng không đủ cho mục đích sản xuất của tôi.

Tôi làm việc trên nền tảng nhắn tin facebook và các ứng dụng nhắn tin cần ít hơn 1 MB để chạy trên nền tảng nhắn tin. Đã cố gắng tìm ra một giải pháp cho cây rung lắc hiệu quả nhưng vẫn không gặp may.


1

Nó hoạt động 100% ng xây dựng --prod --aot --build-tối ưu hóa --vendor-chunk = true


0

Tôi có một ứng dụng khởi động lò xo 5 + góc cạnh (application.properations 1.3+) với sự trợ giúp của nén (liên kết được đính kèm bên dưới) có thể giảm kích thước của kích thước main.bundle.ts từ 2,7 MB xuống 530 KB.

Cũng theo mặc định --aot và --build-tối ưu hóa được bật với chế độ --prod, bạn không cần chỉ định riêng chúng.

https://stackoverflow.com/a/28216983/9491345


0

Kiểm tra xem bạn có cấu hình có tên là "sản xuất" cho ng build --prod không, vì nó là viết tắt của ng build --configuration = sản xuất Không có câu trả lời nào giải quyết được vấn đề của tôi, vì vấn đề nằm ngay trước màn hình. Tôi nghĩ rằng điều này có thể khá phổ biến ... Tôi đã quốc tế hóa ứng dụng với i18n đổi tên tất cả các cấu hình thành ví dụ: sản xuất-en. Sau đó, tôi đã xây dựng với ng build --prod giả sử rằng tối ưu hóa mặc định được sử dụng và phải gần với tối ưu, nhưng thực tế chỉ cần xây dựng ng đã được thực hiện dẫn đến gói 7mb thay vì 250kb.


0

Lấy từ các tài liệu góc v9 ( https://angular.io/guide/workspace-config#alternate-build-configurations ):

Theo mặc định, cấu hình sản xuất được xác định và lệnh ng build có tùy chọn --prod xây dựng bằng cấu hình này. Cấu hình sản xuất đặt mặc định tối ưu hóa ứng dụng theo một số cách, chẳng hạn như gói tệp , giảm thiểu khoảng trắng thừa , xóa nhận xét và mã chết và viết lại mã để sử dụng tên ngắn, mật mã ( "thu nhỏ" ).

Ngoài ra, bạn có thể nén tất cả các triển khai của mình với @ angular-builders / custom-webpack: trình xây dựng trình duyệt trong đó webpack.config.js tùy chỉnh của bạn trông như thế:

module.exports = {
  entry: {
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[hash].js'
  },
  plugins: [
    new CompressionPlugin({
      deleteOriginalAssets: true,
    })
  ]
};

Sau đó, bạn sẽ phải định cấu hình máy chủ web của mình để phân phát nội dung nén, ví dụ với nginx, bạn phải thêm vào nginx.conf:

server {
    gzip on;
    gzip_types      text/plain application/xml;
    gzip_proxied    no-cache no-store private expired auth;
    gzip_min_length 1000;
    ...
}

Trong trường hợp của tôi, thư mục dist đã giảm từ 25 xuống còn 5 mb sau khi chỉ sử dụng --prod trong ng build và sau đó thu nhỏ lại còn 1,5mb sau khi nén.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.