Ai đó có thể giải thích về CommonsChunkPlugin của Webpack không


82

Tôi nhận được ý chính chung là CommonsChunkPluginxem xét tất cả các điểm nhập, kiểm tra xem có các gói / phụ thuộc chung giữa chúng hay không và tách chúng thành gói riêng của chúng.

Vì vậy, giả sử tôi có cấu hình sau:

...
enrty : {
    entry1 : 'entry1.js', //which has 'jquery' as a dependency
    entry2 : 'entry2.js', //which has 'jquery as a dependency
    vendors : [
        'jquery',
        'some_jquery_plugin' //which has 'jquery' as a dependency
    ]
},
output: {
    path: PATHS.build,
    filename: '[name].bundle.js'
}
...

Nếu tôi gói mà không sử dụng CommonsChunkPlugin

Tôi sẽ kết thúc với 3 tệp gói mới:

  • entry1.bundle.jschứa mã hoàn chỉnh từ entry1.jsjqueryvà chứa thời gian chạy của chính nó
  • entry2.bundle.jschứa mã hoàn chỉnh từ entry2.jsjqueryvà chứa thời gian chạy của chính nó
  • vendors.bundle.jschứa mã hoàn chỉnh từ jquerysome_jquery_pluginvà chứa thời gian chạy của chính nó

Điều này rõ ràng là không tốt vì tôi có thể sẽ tải jquery3 lần trong trang, vì vậy chúng tôi không muốn điều đó.

Nếu tôi gói bằng cách sử dụng CommonsChunkPlugin

Tùy thuộc vào đối số mà tôi chuyển cho CommonsChunkPluginbất kỳ đối số nào sau đây sẽ xảy ra:

  • TRƯỜNG HỢP 1: Nếu tôi vượt qua, { name : 'commons' }tôi sẽ kết thúc với các tệp gói sau:

    • entry1.bundle.jschứa mã hoàn chỉnh từ entry1.js, một yêu cầu cho jqueryvà không chứa thời gian chạy
    • entry2.bundle.jschứa mã hoàn chỉnh từ entry2.js, một yêu cầu cho jqueryvà không chứa thời gian chạy
    • vendors.bundle.jschứa mã hoàn chỉnh từ some_jquery_plugin, một yêu cầu cho jqueryvà không chứa thời gian chạy
    • commons.bundle.jschứa mã hoàn chỉnh từ jqueryvà chứa thời gian chạy

    Bằng cách này, chúng tôi kết thúc với một số gói nhỏ hơn về tổng thể và thời gian chạy được chứa trong commonsgói. Khá ổn nhưng không lý tưởng.

  • TRƯỜNG HỢP 2: Nếu tôi vượt qua, { name : 'vendors' }tôi sẽ kết thúc với các tệp gói sau:

    • entry1.bundle.jschứa mã hoàn chỉnh từ entry1.js, một yêu cầu cho jqueryvà không chứa thời gian chạy
    • entry2.bundle.jschứa mã hoàn chỉnh từ entry2.js, một yêu cầu cho jqueryvà không chứa thời gian chạy
    • vendors.bundle.jstrong đó chứa mã hoàn chỉnh từ jquerysome_jquery_pluginvà chứa thời gian chạy.

    Bằng cách này, một lần nữa, chúng tôi kết thúc với một số gói nhỏ hơn về tổng thể nhưng thời gian chạy hiện được chứa trong vendorsgói. Nó tệ hơn một chút so với trường hợp trước, vì thời gian chạy hiện đã nằm trong vendorsgói.

  • TRƯỜNG HỢP 3: Nếu tôi vượt qua, { names : ['vendors', 'manifest'] }tôi sẽ kết thúc với các tệp gói sau:

    • entry1.bundle.jschứa mã hoàn chỉnh từ entry1.js, một yêu cầu cho jqueryvà không chứa thời gian chạy
    • entry2.bundle.jschứa mã hoàn chỉnh từ entry2.js, một yêu cầu cho jqueryvà không chứa thời gian chạy
    • vendors.bundle.jstrong đó chứa mã hoàn chỉnh từ jquerysome_jquery_pluginvà không chứa thời gian chạy
    • manifest.bundle.js chứa các yêu cầu cho mọi gói khác và chứa thời gian chạy

    Bằng cách này, chúng tôi kết thúc với một số gói nhỏ hơn về tổng thể và thời gian chạy được chứa trong manifestgói. Đây là trường hợp lý tưởng.

Điều tôi không hiểu / tôi không chắc mình hiểu

  • Trong CASE 2 tại sao chúng ta kết thúc với vendorsgói chứa cả mã chung ( jquery) và bất cứ thứ gì còn lại từ vendorsmục nhập ( some_jquery_plugin)? Theo hiểu biết của tôi, điều CommonsChunkPluginđã làm ở đây là nó tập hợp mã chung ( jquery) và vì chúng tôi buộc nó phải xuất nó ra vendorsgói, nên nó đã "hợp nhất" mã chung vào vendorsgói (bây giờ chỉ chứa mã từ some_jquery_plugin). Vui lòng xác nhận hoặc giải thích.

  • Trong TRƯỜNG HỢP 3, tôi không hiểu điều gì đã xảy ra khi chúng tôi chuyển { names : ['vendors', 'manifest'] }sang plugin. Tại sao / làm thế nào vendorsgói được giữ nguyên vẹn, chứa cả hai jquerysome_jquery_plugin, khi nào jqueryrõ ràng là một phần phụ thuộc chung và tại sao manifest.bundle.jstệp được tạo được tạo theo cách nó được tạo (yêu cầu tất cả các gói khác và chứa thời gian chạy)?


Đối với trường hợp 1, tôi nghĩ bạn nên chỉ định thuộc tính minChunks.
Marko

10
Tôi đã học được rất nhiều từ câu hỏi của bạn , cảm ơn rất nhiều!
Rafael Eyng,

1
Cảm ơn bạn rất nhiều vì yêu cầu này và thanh toán bù trừ lên nhầm lẫn của tôi suốt thời gian qua trên plugin này ❤
Glenn Mohammad

Có thể ai đó biết, ví dụ này sẽ trông như thế nào trong Webpack 4?
StalkAlex

Câu trả lời:


105

Đây là cách CommonsChunkPluginhoạt động.

Một phần chung "nhận" các mô-đun được chia sẻ bởi một số phần mục nhập. Một ví dụ điển hình về cấu hình phức tạp có thể được tìm thấy trong kho lưu trữ Webpack .

Quá trình CommonsChunkPluginnày được chạy trong giai đoạn tối ưu hóa của Webpack, có nghĩa là nó hoạt động trong bộ nhớ, ngay trước khi các phần được niêm phong và ghi vào đĩa.

Khi một số phần chung được xác định, chúng được xử lý theo thứ tự. Trong trường hợp 3 của bạn, nó giống như chạy plugin hai lần. Nhưng xin lưu ý rằng CommonsChunkPlugincó thể có cấu hình phức tạp hơn (minSize, minChunks, v.v.) ảnh hưởng đến cách các mô-đun được di chuyển.

TRƯỜNG HỢP 1:

  1. Có 3 entrykhối ( entry1, entry2vendors).
  2. Cấu hình đặt commonsđoạn này là một đoạn chung.
  3. Plugin xử lý commonsđoạn mã chung (vì đoạn này không tồn tại nên nó được tạo):
    1. Nó thu thập các module được sử dụng nhiều lần trong các khối khác: entry1, entry2vendorssử dụng jqueryđể mô-đun được lấy ra từ những khối và được thêm vào commonsđoạn.
    2. Các commonsđoạn được đánh dấu như một entryđoạn trong khi entry1, entry2vendorskhối được gắn cờ như entry.
  4. Cuối cùng, vì commonschunk là một entryđoạn nên nó chứa thời gian chạy và jquerymô-đun.

TRƯỜNG HỢP 2:

  1. Có 3 entrykhối ( entry1, entry2vendors).
  2. Cấu hình đặt vendorsđoạn này là một đoạn chung.
  3. Plugin xử lý phần vendorschung:
    1. Nó thu thập các mô-đun được sử dụng nhiều hơn một lần trong các phần khác: entry1entry2sử dụng jqueryđể mô-đun bị xóa khỏi các phần này (lưu ý rằng nó không được thêm vào vendorsphần bởi vì vendorsphần này đã chứa nó).
    2. Các vendorsđoạn được đánh dấu như một entryđoạn trong khi entry1entry2khối được gắn cờ như entry.
  4. Cuối cùng, vì vendorschunk là một entryđoạn, nó chứa thời gian chạy và jquery/ jquery_pluginmô-đun.

TRƯỜNG HỢP 3:

  1. Có 3 entrykhối ( entry1, entry2vendors).
  2. Cấu hình đặt phân vendorsđoạn và phân manifestđoạn là các khối chung.
  3. Plugin tạo ra manifestphần nhỏ vì nó không tồn tại.
  4. Plugin xử lý phần vendorschung:
    1. Nó thu thập các mô-đun được sử dụng nhiều hơn một lần trong các phần khác: entry1entry2sử dụng jqueryđể mô-đun bị xóa khỏi các phần này (lưu ý rằng nó không được thêm vào vendorsphần bởi vì vendorsphần này đã chứa nó).
    2. Các vendorsđoạn được đánh dấu như một entryđoạn trong khi entry1entry2khối được gắn cờ như entry.
  5. Plugin xử lý manifestđoạn mã chung (vì đoạn này không tồn tại nên nó được tạo):
    1. Nó thu thập các mô-đun được sử dụng nhiều hơn một lần trong các phần khác: vì không có mô-đun nào được sử dụng nhiều hơn một lần, không có mô-đun nào được di chuyển.
    2. Các manifestđoạn được đánh dấu là entryđoạn trong khi entry1, entry2vendorsđược gắn cờ như entry.
  6. Cuối cùng, vì manifestchunk là một entryđoạn nên nó chứa thời gian chạy.

Hy vọng nó giúp.


Một vài điều tôi muốn hỏi / làm rõ, vui lòng thêm những điểm này vào câu trả lời của bạn: 1) Bạn có thể thực hiện giải thích từng bước tương tự cho TRƯỜNG HỢP 1 để câu trả lời hoàn thành 1000% không? 2) Chạy plugin với { names : ['vendors', 'manifest'] }giống như chạy nó hai lần, một lần với { name : 'vendors' }và một lần với { name : 'manifest' }, đúng không? 3) Khi chúng ta nói "Plugin xử lý một đoạn chung", chúng ta có nghĩa là nó tạo ra nội dung mà nó sẽ lấy ra trong bundle.jstệp, trong bộ nhớ, đúng không? 4) Cho đến khi nó được "xử lý tất cả các khối chung" nó đã không viết bất kỳ đầu ra vào một tập tin ở tất cả, đó là tất cả trong bộ nhớ
Dimitris Karagiannis

2
Tôi có một câu hỏi nữa, nếu bạn muốn trả lời. Giả sử trong ví dụ của tôi ở trên, entry1.jsentry2.jscó một tệp chung khác giữa chúng, ngoài jquerytệp, hãy gọi nó ownLib.js. Trong CASE 2 và CASE 3, ownLib.jssẽ kết thúc vendors.bundle.jsđúng? Bạn sẽ làm như thế nào để các tệp thông thường khác với tệp của nhà cung cấp được tách thành phần riêng của chúng, ngoài vendorsphần này? Xin lỗi vì làm phiền bạn, nhưng tôi vẫn đang học cách sử dụng webpack
Dimitris Karagiannis

7
Vâng, đúng vậy: ownLib.jssẽ được đặt trong khối chung đầu tiên. Nếu bạn muốn thu thập phụ thuộc phổ biến ở chunck khác, bạn phải vượt qua một cái gì đó như thế này: { names : ['common', 'vendors', 'manifest'] }.
Laurent Etiemble

6
Câu hỏi tuyệt vời, câu trả lời tuyệt vời, cuộc thảo luận tuyệt vời. Có vẻ như cuối cùng thì tôi cũng hiểu rồi.
oluckyman

3
Tôi đã dành cả ngày cuối cùng để đọc tài liệu CommonsChunkPlugin và đây là nơi đầu tiên tôi đọc rằng, sau khi thực thi, các phần được xử lý "không được gắn thẻ là mục nhập". Điều đó về cơ bản giải thích mọi thứ mà tôi gặp khó khăn - nếu tôi có thể ủng hộ nhiều hơn một lần, tôi sẽ làm vậy.
Coderer
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.