Tách mã là một trong những tính năng hấp dẫn nhất của webpack. Tính năng này cho phép bạn chia mã của mình thành nhiều gói khác nhau, sau đó có thể được tải theo yêu cầu hoặc song song. Nó có thể được sử dụng để đạt được các gói nhỏ hơn và kiểm soát mức độ ưu tiên tải tài nguyên, nếu được sử dụng đúng cách, có thể có tác động lớn đến thời gian tải
Có ba cách tiếp cận chung để tách mã có sẵn
- các điểm nhập cảnh. Tách mã thủ công bằng cách sử dụng cấu hình
5import _ from 'lodash'; console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
- Ngăn chặn trùng lặp. Sử dụng hoặc
6 để loại bỏ và tách khốiimport _ from 'lodash'; console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
- Nhập động. Tách mã thông qua các lệnh gọi hàm nội tuyến trong các mô-đun
các điểm nhập cảnh
Đây là cách dễ nhất và trực quan nhất để tách mã. Tuy nhiên, nó thủ công hơn và có một số cạm bẫy, chúng ta sẽ xem qua. Hãy xem cách chúng ta có thể tách một mô-đun khác khỏi gói chính
dự định
webpack-demo
|- package.json
|- package-lock.json
|- webpack.config.js
|- /dist
|- /src
|- index.js
+ |- another-module.js
|- /node_modules
mô-đun khác. js
import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
gói web. cấu hình. js
const path = require['path'];
module.exports = {
- entry: './src/index.js',
+ mode: 'development',
+ entry: {
+ index: './src/index.js',
+ another: './src/another-module.js',
+ },
output: {
- filename: 'main.js',
+ filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
Điều này sẽ mang lại kết quả xây dựng sau
...
[webpack-cli] Compilation finished
asset index.bundle.js 553 KiB [emitted] [name: index]
asset another.bundle.js 553 KiB [emitted] [name: another]
runtime modules 2.49 KiB 12 modules
cacheable modules 530 KiB
./src/index.js 257 bytes [built] [code generated]
./src/another-module.js 84 bytes [built] [code generated]
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.4.0 compiled successfully in 245 ms
Như đã đề cập, có một số cạm bẫy đối với phương pháp này
- Nếu có bất kỳ mô-đun trùng lặp nào giữa các khối mục nhập, chúng sẽ được bao gồm trong cả hai gói
- Nó không linh hoạt và không thể được sử dụng để phân tách động mã với logic ứng dụng cốt lõi
Điểm đầu tiên trong hai điểm này chắc chắn là một vấn đề đối với ví dụ của chúng tôi, vì
import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
7 cũng được nhập trong import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
8 và do đó sẽ được sao chép trong cả hai gói. Hãy loại bỏ sự trùng lặp này trong phần tiếp theophụ thuộc đầu vào
Cho phép chia sẻ các mô-đun giữa các khối
gói web. cấu hình. js
ngày thứ 8Nếu chúng tôi định sử dụng nhiều điểm vào trên một trang HTML, thì cũng cần có ____ ______, nếu không chúng tôi có thể gặp rắc rối được mô tả tại đây
gói web. cấu hình. js
import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
0Và đây là kết quả của việc xây dựng
import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
1Như bạn có thể thấy, có một tệp
const path = require['path'];
module.exports = {
- entry: './src/index.js',
+ mode: 'development',
+ entry: {
+ index: './src/index.js',
+ another: './src/another-module.js',
+ },
output: {
- filename: 'main.js',
+ filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
1 khác được tạo bên cạnh const path = require['path'];
module.exports = {
- entry: './src/index.js',
+ mode: 'development',
+ entry: {
+ index: './src/index.js',
+ another: './src/another-module.js',
+ },
output: {
- filename: 'main.js',
+ filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
2, const path = require['path'];
module.exports = {
- entry: './src/index.js',
+ mode: 'development',
+ entry: {
+ index: './src/index.js',
+ another: './src/another-module.js',
+ },
output: {
- filename: 'main.js',
+ filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
3 và const path = require['path'];
module.exports = {
- entry: './src/index.js',
+ mode: 'development',
+ entry: {
+ index: './src/index.js',
+ another: './src/another-module.js',
+ },
output: {
- filename: 'main.js',
+ filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
4Mặc dù cho phép sử dụng nhiều điểm nhập trên mỗi trang trong webpack, nhưng nên tránh sử dụng khi có thể để ưu tiên một điểm nhập có nhiều lần nhập.
const path = require['path'];
module.exports = {
- entry: './src/index.js',
+ mode: 'development',
+ entry: {
+ index: './src/index.js',
+ another: './src/another-module.js',
+ },
output: {
- filename: 'main.js',
+ filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
5. Điều này dẫn đến việc tối ưu hóa tốt hơn và thứ tự thực thi nhất quán khi sử dụng thẻ tập lệnh const path = require['path'];
module.exports = {
- entry: './src/index.js',
+ mode: 'development',
+ entry: {
+ index: './src/index.js',
+ another: './src/another-module.js',
+ },
output: {
- filename: 'main.js',
+ filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
6SplitChunksPlugin
import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
6 cho phép chúng tôi trích xuất các phụ thuộc phổ biến vào một đoạn mục nhập hiện có hoặc một đoạn hoàn toàn mới. Hãy sử dụng điều này để khử trùng lặp phụ thuộc import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
7 từ ví dụ trướcgói web. cấu hình. js
webpack-demo
|- package.json
|- package-lock.json
|- webpack.config.js
|- /dist
|- /src
|- index.js
+ |- another-module.js
|- /node_modules
0Với tùy chọn cấu hình tại chỗ, bây giờ chúng ta sẽ thấy phần phụ thuộc trùng lặp đã bị xóa khỏi
const path = require['path'];
module.exports = {
- entry: './src/index.js',
+ mode: 'development',
+ entry: {
+ index: './src/index.js',
+ another: './src/another-module.js',
+ },
output: {
- filename: 'main.js',
+ filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
3 và const path = require['path'];
module.exports = {
- entry: './src/index.js',
+ mode: 'development',
+ entry: {
+ index: './src/index.js',
+ another: './src/another-module.js',
+ },
output: {
- filename: 'main.js',
+ filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
4 của chúng ta. Plugin sẽ lưu ý rằng chúng tôi đã tách import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
7 thành một đoạn riêng biệt và loại bỏ trọng lượng chết khỏi gói chính của chúng tôi. Hãy làm một ...
[webpack-cli] Compilation finished
asset index.bundle.js 553 KiB [emitted] [name: index]
asset another.bundle.js 553 KiB [emitted] [name: another]
runtime modules 2.49 KiB 12 modules
cacheable modules 530 KiB
./src/index.js 257 bytes [built] [code generated]
./src/another-module.js 84 bytes [built] [code generated]
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.4.0 compiled successfully in 245 ms
3 để xem nó có hoạt động khôngwebpack-demo
|- package.json
|- package-lock.json
|- webpack.config.js
|- /dist
|- /src
|- index.js
+ |- another-module.js
|- /node_modules
5Dưới đây là một số plugin và trình tải hữu ích khác do cộng đồng cung cấp để tách mã
Nhập động
Hai kỹ thuật tương tự được webpack hỗ trợ khi phân tách mã động. Cách tiếp cận đầu tiên và được đề xuất là sử dụng phương pháp phù hợp với đề xuất ECMAScript để nhập động. Cách tiếp cận kế thừa dành riêng cho webpack là sử dụng. Hãy thử sử dụng cách đầu tiên trong hai cách tiếp cận này
Trước khi chúng tôi bắt đầu, hãy loại bỏ thêm
import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
5 và const path = require['path'];
module.exports = {
- entry: './src/index.js',
+ mode: 'development',
+ entry: {
+ index: './src/index.js',
+ another: './src/another-module.js',
+ },
output: {
- filename: 'main.js',
+ filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
9 khỏi cấu hình của chúng tôi trong ví dụ trên vì chúng sẽ không cần thiết cho phần trình diễn tiếp theo nàygói web. cấu hình. js
webpack-demo
|- package.json
|- package-lock.json
|- webpack.config.js
|- /dist
|- /src
|- index.js
+ |- another-module.js
|- /node_modules
8Chúng tôi cũng sẽ cập nhật dự án của mình để xóa các tệp hiện không sử dụng
dự định
import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
0Bây giờ, thay vì nhập tĩnh
import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
7, chúng tôi sẽ sử dụng nhập động để tách một đoạnsrc/chỉ mục. js
import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
1Lý do chúng tôi cần
...
[webpack-cli] Compilation finished
asset index.bundle.js 553 KiB [emitted] [name: index]
asset another.bundle.js 553 KiB [emitted] [name: another]
runtime modules 2.49 KiB 12 modules
cacheable modules 530 KiB
./src/index.js 257 bytes [built] [code generated]
./src/another-module.js 84 bytes [built] [code generated]
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.4.0 compiled successfully in 245 ms
9 là vì webpack 4, khi nhập mô-đun CommonJS, quá trình nhập sẽ không còn phân giải thành giá trị của const path = require['path'];
module.exports = {
mode: 'development',
entry: {
- index: './src/index.js',
- another: './src/another-module.js',
+ index: {
+ import: './src/index.js',
+ dependOn: 'shared',
+ },
+ another: {
+ import: './src/another-module.js',
+ dependOn: 'shared',
+ },
+ shared: 'lodash',
},
output: {
filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
0, thay vào đó, nó sẽ tạo một đối tượng không gian tên nhân tạo cho mô-đun CommonJS. Để biết thêm thông tin về lý do đằng sau điều này, hãy đọc webpack 4. nhập[] và CommonJsHãy chạy webpack để xem
import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
7 được tách ra thành một gói riêngimport _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
2Khi
...
[webpack-cli] Compilation finished
asset index.bundle.js 553 KiB [emitted] [name: index]
asset another.bundle.js 553 KiB [emitted] [name: another]
runtime modules 2.49 KiB 12 modules
cacheable modules 530 KiB
./src/index.js 257 bytes [built] [code generated]
./src/another-module.js 84 bytes [built] [code generated]
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.4.0 compiled successfully in 245 ms
4 trả về một lời hứa, nó có thể được sử dụng với các hàm của const path = require['path'];
module.exports = {
- entry: './src/index.js',
+ mode: 'development',
+ entry: {
+ index: './src/index.js',
+ another: './src/another-module.js',
+ },
output: {
- filename: 'main.js',
+ filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
6. Đây là cách nó sẽ đơn giản hóa mãsrc/chỉ mục. js
import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
3Tìm nạp trước/Tải trước mô-đun
Gói web 4. 6. 0+ thêm hỗ trợ cho tìm nạp trước và tải trước
Sử dụng các lệnh nội tuyến này trong khi khai báo quá trình nhập của bạn cho phép gói web xuất ra “Gợi ý tài nguyên” cho trình duyệt biết rằng đối với
- tìm nạp trước. tài nguyên có lẽ là cần thiết cho một số điều hướng trong tương lai
- tải trước. tài nguyên cũng sẽ cần thiết trong quá trình điều hướng hiện tại
Một ví dụ về điều này là có thành phần
const path = require['path'];
module.exports = {
mode: 'development',
entry: {
- index: './src/index.js',
- another: './src/another-module.js',
+ index: {
+ import: './src/index.js',
+ dependOn: 'shared',
+ },
+ another: {
+ import: './src/another-module.js',
+ dependOn: 'shared',
+ },
+ shared: 'lodash',
},
output: {
filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
4, thành phần này hiển thị thành phần const path = require['path'];
module.exports = {
mode: 'development',
entry: {
- index: './src/index.js',
- another: './src/another-module.js',
+ index: {
+ import: './src/index.js',
+ dependOn: 'shared',
+ },
+ another: {
+ import: './src/another-module.js',
+ dependOn: 'shared',
+ },
+ shared: 'lodash',
},
output: {
filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
5, sau đó theo yêu cầu sẽ tải thành phần const path = require['path'];
module.exports = {
mode: 'development',
entry: {
- index: './src/index.js',
- another: './src/another-module.js',
+ index: {
+ import: './src/index.js',
+ dependOn: 'shared',
+ },
+ another: {
+ import: './src/another-module.js',
+ dependOn: 'shared',
+ },
+ shared: 'lodash',
},
output: {
filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
6 sau khi được nhấpnút đăng nhập. js
Điều này sẽ dẫn đến việc
const path = require['path'];
module.exports = {
mode: 'development',
entry: {
- index: './src/index.js',
- another: './src/another-module.js',
+ index: {
+ import: './src/index.js',
+ dependOn: 'shared',
+ },
+ another: {
+ import: './src/another-module.js',
+ dependOn: 'shared',
+ },
+ shared: 'lodash',
},
output: {
filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
7 được thêm vào phần đầu của trang, điều này sẽ hướng dẫn trình duyệt tìm nạp trước tệp const path = require['path'];
module.exports = {
mode: 'development',
entry: {
- index: './src/index.js',
- another: './src/another-module.js',
+ index: {
+ import: './src/index.js',
+ dependOn: 'shared',
+ },
+ another: {
+ import: './src/another-module.js',
+ dependOn: 'shared',
+ },
+ shared: 'lodash',
},
output: {
filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
8 trong thời gian nhàn rỗiChỉ thị tải trước có nhiều điểm khác biệt so với tìm nạp trước
- Một đoạn được tải trước bắt đầu tải song song với đoạn gốc. Đoạn tìm nạp trước bắt đầu sau khi đoạn gốc tải xong
- Một đoạn được tải trước có mức độ ưu tiên trung bình và được tải xuống ngay lập tức. Một đoạn tìm nạp trước được tải xuống trong khi trình duyệt không hoạt động
- Một đoạn được tải trước phải được yêu cầu ngay lập tức bởi đoạn gốc. Một đoạn tìm nạp trước có thể được sử dụng bất cứ lúc nào trong tương lai
- Hỗ trợ trình duyệt là khác nhau
Một ví dụ về điều này có thể là có một
const path = require['path'];
module.exports = {
mode: 'development',
entry: {
- index: './src/index.js',
- another: './src/another-module.js',
+ index: {
+ import: './src/index.js',
+ dependOn: 'shared',
+ },
+ another: {
+ import: './src/another-module.js',
+ dependOn: 'shared',
+ },
+ shared: 'lodash',
},
output: {
filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
9 luôn phụ thuộc vào một thư viện lớn nên nằm trong một đoạn riêng biệtHãy tưởng tượng một thành phần
import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
00 cần một import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
01 khổng lồ. Nó hiển thị một import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
02 khi được kết xuất và ngay lập tức thực hiện nhập khẩu theo yêu cầu của import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
01Thành phần biểu đồ. js
Khi một trang sử dụng
import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
00 được yêu cầu, chart-library-chunk cũng được yêu cầu thông qua const path = require['path'];
module.exports = {
mode: 'development',
entry: {
- index: './src/index.js',
- another: './src/another-module.js',
+ index: {
+ import: './src/index.js',
+ dependOn: 'shared',
+ },
+ another: {
+ import: './src/another-module.js',
+ dependOn: 'shared',
+ },
+ shared: 'lodash',
},
output: {
filename: '[name].bundle.js',
path: path.resolve[__dirname, 'dist'],
},
};
7. Giả sử đoạn trang nhỏ hơn và kết thúc nhanh hơn, trang sẽ được hiển thị với import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
02, cho đến khi kết thúc import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
07 đã được yêu cầu. Điều này sẽ giúp tăng thời gian tải một chút vì nó chỉ cần một chuyến khứ hồi thay vì hai. Đặc biệt là trong môi trường có độ trễ caoĐôi khi bạn cần có quyền kiểm soát tải trước của riêng mình. Ví dụ: tải trước bất kỳ quá trình nhập động nào có thể được thực hiện thông qua tập lệnh async. Điều này có thể hữu ích trong trường hợp kết xuất phía máy chủ phát trực tuyến
Nếu quá trình tải tập lệnh không thành công trước khi webpack bắt đầu tự tải tập lệnh đó [webpack chỉ tạo thẻ tập lệnh để tải mã của nó, nếu tập lệnh đó không có trên trang], trình xử lý bắt đó sẽ không bắt đầu cho đến khi không được thông qua. Hành vi này có thể bất ngờ. Nhưng điều đó có thể giải thích được - webpack không thể đưa ra bất kỳ lỗi nào, vì webpack không biết, tập lệnh đó không thành công. Webpack sẽ thêm trình xử lý lỗi vào tập lệnh ngay sau khi xảy ra lỗi
Để ngăn chặn sự cố như vậy, bạn có thể thêm trình xử lý onerror của riêng mình, trình xử lý này sẽ xóa tập lệnh trong trường hợp có bất kỳ lỗi nào
import _ from 'lodash';
console.log[_.join[['Another', 'module', 'loaded!'], ' ']];
4Trong trường hợp đó, tập lệnh bị lỗi sẽ bị xóa. Webpack sẽ tạo tập lệnh riêng và mọi lỗi sẽ được xử lý mà không có bất kỳ thời gian chờ nào
Phân tích gói
Khi bạn bắt đầu tách mã của mình, có thể hữu ích khi phân tích đầu ra để kiểm tra xem các mô-đun đã kết thúc ở đâu. Công cụ phân tích chính thức là một nơi tốt để bắt đầu. Ngoài ra còn có một số tùy chọn khác được cộng đồng hỗ trợ
- biểu đồ webpack. Biểu đồ hình tròn tương tác cho số liệu thống kê webpack
- trình hiển thị webpack. Trực quan hóa và phân tích các gói của bạn để xem mô-đun nào đang chiếm dung lượng và mô-đun nào có thể trùng lặp
- trình phân tích gói webpack. Tiện ích plugin và CLI đại diện cho nội dung gói dưới dạng sơ đồ cây có thể thu phóng tương tác thuận tiện
- trình trợ giúp tối ưu hóa gói gói web. Công cụ này sẽ phân tích gói của bạn và cung cấp cho bạn các đề xuất khả thi về những điều cần cải thiện để giảm kích thước gói của bạn
- thống kê bó. Tạo báo cáo gói [kích thước gói, nội dung, mô-đun] và so sánh kết quả giữa các bản dựng khác nhau
bước tiếp theo
Xem Lazy Loading để biết ví dụ cụ thể hơn về cách sử dụng
...
[webpack-cli] Compilation finished
asset index.bundle.js 553 KiB [emitted] [name: index]
asset another.bundle.js 553 KiB [emitted] [name: another]
runtime modules 2.49 KiB 12 modules
cacheable modules 530 KiB
./src/index.js 257 bytes [built] [code generated]
./src/another-module.js 84 bytes [built] [code generated]
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.4.0 compiled successfully in 245 ms
4 trong ứng dụng thực và bộ nhớ đệm để tìm hiểu cách phân tách mã hiệu quả hơn