τα στοιχεία επικοινωνίας μου
Ταχυδρομείο[email protected]
2024-07-08
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Εκτός από την κύρια διαδικασία, θα εξηγήσουμε επίσης πολλές ασαφείς έννοιες λεπτομερώς:
μπροστά Init, Make, Seal"Στο ", έχουμε εισαγάγει ότι η υποκείμενη κατασκευαστική λογική του Webpack μπορεί χονδρικά να χωριστεί σε:Αρχικοποίηση, κατασκευή, συσκευασία«τρεις φάσεις:
σε,"Κατασκευάσει«Η φάση είναι υπεύθυνη για την ανάλυση των εξαρτήσεων μεταξύ των ενοτήτων και την καθιέρωση του Γράφημα εξάρτησης(ModuleGraph στη συνέχεια, στο "?Ενθυλάκωση" στάδιο, με βάση το γράφημα εξάρτησης, οι μονάδες ενσωματώνονται χωριστά σε πολλά αντικείμενα Chunk και οι σχέσεις εξάρτησης γονέα-παιδιού μεταξύ των Chunks ταξινομούνται σε ChunkGraph και αρκετά αντικείμενα ChunkGroup.
Ο πιο σημαντικός στόχος της φάσης "ενθυλάκωσης" είναι η κατασκευή του γραφήματος σχέσεων ChunkGraph με βάση το γράφημα σχέσεων ModuleGraph που συλλέγεται στη φάση "κατασκευής".
Ας αναλύσουμε εν συντομία τη λογική υλοποίησης πολλών σημαντικών βημάτων εδώ.
Το πρώτο βήμα είναι πολύ κρίσιμο: ΜΕΤΑΦΟΡΑseal()
Μετά τη λειτουργία, τραβέρσαentry
Διαμόρφωση, δημιουργήστε ένα κενό για κάθε καταχώρησηChunk
καιΣημείο εισόδου αντικείμενο (ένα ειδικόChunkGroup
), και αρχικά ρυθμίστε το βασικό ChunkGraph
Δομική σχέση, προετοιμασία για το επόμενο βήμα, κωδικός κλειδιού:
class Compilation {
seal(callback) {
// ...
const chunkGraphInit = new Map();
// 遍历入口模块列表
for (const [name, { dependencies, includeDependencies, options }] of this
.entries) {
// 为每一个 entry 创建对应的 Chunk 对象
const chunk = this.addChunk(name);
// 为每一个 entry 创建对应的 ChunkGroup 对象
const entrypoint = new Entrypoint(options);
// 关联 Chunk 与 ChunkGroup
connectChunkGroupAndChunk(entrypoint, chunk);
// 遍历 entry Dependency 列表
for (const dep of [...this.globalEntry.dependencies, ...dependencies]) {
// 为每一个 EntryPoint 关联入口依赖对象,以便下一步从入口依赖开始遍历其它模块
entrypoint.addOrigin(null, { name }, /** @type {any} */ (dep).request);
const module = this.moduleGraph.getModule(dep);
if (module) {
// 在 ChunkGraph 中记录入口模块与 Chunk 关系
chunkGraph.connectChunkAndEntryModule(chunk, module, entrypoint);
// ...
}
}
}
// 调用 buildChunkGraph 方法,开始构建 ChunkGraph
buildChunkGraph(this, chunkGraphInit);
// 触发各种优化钩子
// ...
}
}
Αφού ολοκληρωθεί η εκτέλεση, σχηματίζεται η ακόλουθη δομή δεδομένων:
Δεύτερον, εάν έχει ρυθμιστεί αυτή τη στιγμή entry.runtime
, το Webpack θα παρέχει επίσης κώδικα χρόνου εκτέλεσης σε αυτό το στάδιο δημιουργώ Το αντίστοιχο Chunk και απευθείαςδιανέμω Δίνωentry
αντίστοιχοςChunkGroup
αντικείμενο.Τηλεφώνησε όταν όλα είναι έτοιμαbuildChunkGraph λειτουργία, μεταβείτε στο επόμενο βήμα.
Βήμα δυο: υπάρχειbuildChunkGraph
εντός λειτουργίαςΜΕΤΑΦΟΡΑ visitModules
Λειτουργήστε, διασχίστε το ModuleGraph και αντιστοιχίστε όλες τις μονάδες σε διαφορετικές ενότητες ανάλογα με τις εξαρτήσεις τους.Chunk
Αντικείμενο, εάν συναντηθεί κατά τη διάρκεια αυτής της διαδικασίαςασύγχρονη μονάδα, μετά το module δημιουργώνέος ChunkGroup
καιChunk
Αντικείμενο, σχηματίζοντας τελικά την ακόλουθη δομή δεδομένων:
τρίτο βήμα: υπάρχειbuildChunkGraph
σε λειτουργίαΜΕΤΑΦΟΡΑ connectChunkGroups
μέθοδος, καθιερώνωChunkGroup
μεταξύ,Chunk
εξαρτήσεις μεταξύ τους για να δημιουργήσουν ένα πλήρεςChunkGraph
Αντικείμενο, σχηματίζοντας τελικά την ακόλουθη δομή δεδομένων:
το τέταρτο βήμα: υπάρχειbuildChunkGraph
σε λειτουργίαΜΕΤΑΦΟΡΑ cleanupUnconnectedGroups
Μέθοδος, η εκκαθάριση δεν είναι έγκυρηChunkGroup
, παίζει κυρίως ρόλο στη βελτιστοποίηση της απόδοσης.
Αφού περάσετε από αυτά τα τέσσερα βήματα από πάνω προς τα κάτω,ModuleGraph
Οι μονάδες που είναι αποθηκευμένες στο θα εκχωρηθούν σε τρία διαφορετικά αντικείμενα Chunk: Entry, Async και Runtime ανάλογα με τη φύση της ίδιας της ενότητας και οι εξαρτήσεις μεταξύ των Chunk θα αποθηκευτούν στις συλλογές ChunkGraph και ChunkGroup. Μπορείτε να συνεχίσετε με βάση αυτά τα αντικείμενα αργότερα Τροποποιήστε τις πολιτικές υπεργολαβίας (π.χ.SplitChunksPlugin
), πραγματοποιήστε βελτιστοποίηση υπεργολαβίας με την αναδιοργάνωση και την κατανομή της ιδιοκτησίας των αντικειμένων Module και Chunk.
Η παραπάνω διαδικασία κατασκευής περιλαμβάνει τρία βασικά αντικείμενα: Chunk, ChunkGroup και ChunkGraph Ας συνοψίσουμε πρώτα τις έννοιες και τις λειτουργίες τους για να εμβαθύνουμε την κατανόησή μας:
Chunk
: Η μονάδα χρησιμοποιείται για την ανάγνωση του περιεχομένου της ενότητας, την καταγραφή εξαρτήσεων μεταξύ των μονάδων, κ.λπ., ενώ το Chunk συγχωνεύει πολλαπλές ενότητες με βάση τις εξαρτήσεις λειτουργιών και τις εξάγει σε αρχεία στοιχείων (η λογική της συγχώνευσης και της παραγωγής προϊόντων θα εξηγηθεί στο επόμενο κεφάλαιο):ChunkGroup
:ένας ChunkGroup
περιέχει ένα ή περισσότεραChunk
αντικείμενο;ChunkGroup
καιChunkGroup
Μια σχέση εξάρτησης γονέα-παιδιού διαμορφώνεται μεταξύ:ChunkGraph
: Τέλος, το Webpack θα αποθηκεύσει τις εξαρτήσεις μεταξύ των Chunks και των ChunkGroups compilation.chunkGraph
Στο αντικείμενο, σχηματίζονται οι ακόλουθες σχέσεις τύπου:Τα παραπάνω ChunkGraph
Η διαδικασία κατασκευής θα οργανώσει τελικά το Module σε τρεις διαφορετικούς τύπους Chunks:
entry
Οι μονάδες στις οποίες φτάνει το κάτω άγγιγμα οργανώνονται σε ένα κομμάτι.entry.runtime
Όταν δεν είναι κενή, η ενότητα χρόνου εκτέλεσης θα οργανωθεί σε ένα Chunk.Αυτό είναι ενσωματωμένο στο Webpack, εάν δεν χρησιμοποιείται splitChunks
Στην περίπτωση άλλων προσθηκών, οι προεπιλεγμένοι κανόνες για την αντιστοίχιση της εισόδου της μονάδας στην έξοδο είναι μία από τις βασικές βασικές αρχές του Webpack, επομένως είναι απαραίτητο να εισαχθούν οι συγκεκριμένοι κανόνες για κάθε Τσάνκ.
Κομμάτι εισόδου:
Ξεκινώντας με το Entry Chunk, το Webpack θα πρώτα entry
δημιουργώChunk
Αντιγράψτε, για παράδειγμα, την ακόλουθη διαμόρφωση:
module.exports = {
entry: {
main: "./src/main",
home: "./src/home",
}
};
Διασχίζω entry
ιδιότητες αντικειμένου και δημιουργίαchunk[main]
、chunk[home]
Δύο αντικείμενα, αυτή τη στιγμή περιέχουν τα δύο Κομμάτια αντίστοιχαmain
、home
Μονάδα μέτρησης:
Αφού ολοκληρωθεί η προετοιμασία, το Webpack θα ModuleGraph
δεδομένα εξάρτησης, θαentry
Όλες οι ενότητες που αγγίζονται από τα παρακάτω τοποθετούνται στο Τσάνκ (που εμφανίζεται μέσαvisitModules μέθοδος), για παράδειγμα, για τις ακόλουθες εξαρτήσεις αρχείων:
main.js
Εάν τα τέσσερα αρχεία a/b/c/d αναφέρονται άμεσα ή έμμεσα ταυτόχρονα, το Webpack θαmain.js
Η ενότητα δημιουργεί αντικείμενα Chunk και EntryPoint και, στη συνέχεια, προσθέτει σταδιακά στοιχεία a/b/c/d σεchunk[main]
, σχηματίζοντας τελικά:
Ασύγχρονο κομμάτι:
Δεύτερον, το Webpack θα μεταγλωττίσει κάθε δήλωση ασύγχρονης εισαγωγής (import(xxx)
καιrequire.ensure
) επεξεργάζεται ως ξεχωριστό αντικείμενο Chunk και όλες οι υπομονάδες του προστίθενται σε αυτό το Chunk - το ονομάζουμε Async Chunk. Για παράδειγμα, για το ακόλουθο παράδειγμα:
// index.js
import './sync-a.js'
import './sync-b.js'
import('./async-a.js')
// async-a.js
import './sync-c.js'
Στην ενότητα εισαγωγής index.js
Στο, το sync-a και το sync-b εισάγονται με σύγχρονο τρόπο, η μονάδα async-a εισάγεται με έναν ασύγχρονο τρόπο.sync-c
ενότητα, σχηματίζοντας το ακόλουθο διάγραμμα εξάρτησης ενότητας:
Σε αυτό το σημείο, το Webpack θα είναι το σημείο εισόδου index.js
, ασύγχρονη μονάδα async-a.js
Δημιουργήστε υποπακέτα ξεχωριστά για να σχηματίσετε την ακόλουθη δομή Chunk:
και chunk[index]
καιchunk[async-a]
Δημιουργείται μια μονόδρομη εξάρτηση μεταξύ τους και το Webpack θα αποθηκεύσει αυτήν την εξάρτησηChunkGroup._parents
、ChunkGroup._children
σε ακίνητα.
Κομμάτι χρόνου εκτέλεσης:
Τέλος, εκτός entry
, Εκτός από τις ασύγχρονες μονάδες, το Webpack5 υποστηρίζει επίσης την εξαγωγή κώδικα χρόνου εκτέλεσης ξεχωριστά σε Chunks. Ο κώδικας χρόνου εκτέλεσης που αναφέρεται εδώ αναφέρεται σε μια σειρά βασικών κωδικών πλαισίου που εισάγονται από το Webpack για να διασφαλιστεί ότι το συσκευασμένο προϊόν μπορεί να εκτελεστεί κανονικά.
Το μεγάλο τμήμα κώδικα που κυκλώνεται στο κόκκινο πλαίσιο στην παραπάνω εικόνα είναι ο κώδικας χρόνου εκτέλεσης που δημιουργείται δυναμικά από το Webpack Κατά τη μεταγλώττιση, το Webpack θα αποφασίσει ποιον κώδικα χρόνου εκτέλεσης θα εξάγει με βάση τον επιχειρηματικό κώδικα (με βάσηDependency
υποκατηγορία), για παράδειγμα:
__webpack_require__.f
、__webpack_require__.r
και άλλες λειτουργίες για την επίτευξη ελάχιστης αρθρωτής υποστήριξης.__webpack_require__.e
λειτουργία;__webpack_require__.o
λειτουργία;Αν και κάθε κομμάτι του κώδικα χρόνου εκτέλεσης μπορεί να είναι μικρό, καθώς οι δυνατότητες αυξάνονται, το τελικό αποτέλεσμα θα γίνεται όλο και μεγαλύτερο entry.runtime
Τα στοιχεία διαμόρφωσης χρησιμοποιούνται για να δηλώσουν πώς συσκευάζεται ο κώδικας χρόνου εκτέλεσης.Για χρήση, απλώς χρησιμοποιήστεentry
Προσθήκη φόρμας συμβολοσειράς στο αντικείμενοruntime
τιμή, για παράδειγμα:
module.exports = {
entry: {
index: { import: "./src/index", runtime: "solid-runtime" },
}
};
υπάρχει compilation.seal
Στη συνάρτηση, το Webpack είναι πρώταentry
δημιουργώEntryPoint
, μετά κρίνετε entry
Περιέχει η διαμόρφωσηruntime
ιδιότητες, εάν υπάρχουν, δημιουργήστε τις μεruntime
Η τιμή είναι το όνομα του κομματιού. Επομένως, η παραπάνω διαμόρφωση παραδείγματος θα δημιουργήσει δύο κομμάτια:chunk[index.js]
、chunk[solid-runtime]
, και με βάση αυτό, τελικά εξάγονται δύο αρχεία:
index.js
έγγραφο;solid-runtime.js
έγγραφο.σε ΠΟΛΛΟΥΣ entry
Στο σενάριο, μόνο για τον καθέναentry
Όλα τα ίδιαruntime
τιμή, ο κώδικας χρόνου εκτέλεσης Webpack θα συγχωνευθεί και θα γραφτεί στο ίδιο Runtime Chunk, επιτυγχάνοντας τελικά τη βελτιστοποίηση της απόδοσης του προϊόντος. Για παράδειγμα, για την ακόλουθη διαμόρφωση:
module.exports = {
entry: {
index: { import: "./src/index", runtime: "solid-runtime" },
home: { import: "./src/home", runtime: "solid-runtime" },
}
};
Είσοδος index
、home
μοιραστείτε τα ίδιαruntime
αξία και τελικά δημιουργούν τρία κομμάτια, αντίστοιχα:
Είσοδος αυτή την ώρα chunk[index]
、chunk[home]
με χρόνο εκτέλεσηςchunk[solid-runtime]
Θα δημιουργηθεί επίσης σχέση εξάρτησης γονέα-παιδιού.
Το μεγαλύτερο πρόβλημα με τους προεπιλεγμένους κανόνες υποσυσκευασίας είναι ότι δεν μπορεί να λύσει την αντιγραφή της ενότητας Εάν πολλά κομμάτια περιέχουν την ίδια μονάδα ταυτόχρονα, τότε αυτή η ενότητα θα συσκευαστεί επανειλημμένα σε αυτά τα Τεμάχια χωρίς περιορισμούς. Για παράδειγμα, ας υποθέσουμε ότι έχουμε δύο καταχωρήσεις main/index που και οι δύο εξαρτώνται από την ίδια ενότητα:
Από προεπιλογή, το Webpack δεν θα κάνει πρόσθετη επεξεργασία σε αυτό, αλλά απλώς συσκευάζει τη λειτουργική μονάδα c στο κύριο/ευρετήριο δύο Τεμάχια ταυτόχρονα, σχηματίζοντας τελικά:
μπορεί να ειδωθεί chunk
είναι απομονωμένα μεταξύ τους, η ενότητα c συσκευάζεται επανειλημμένα, γεγονός που μπορεί να προκαλέσει περιττή απώλεια απόδοσης στο τελικό προϊόν!
Για την επίλυση αυτού του προβλήματος, παρουσιάστηκε το Webpack 3 CommonChunkPlugin
Το πρόσθετο επιχειρεί να εξαγάγει κοινές εξαρτήσεις μεταξύ των καταχωρήσεων σε ξεχωριστέςchunk
,αλλά CommonChunkPlugin
Ουσιαστικά υλοποιείται με βάση την απλή αλυσίδα σχέσεων γονέα-παιδιού μεταξύ των Chunks. Είναι δύσκολο να συναχθεί ότι το εξαγόμενο τρίτο πακέτο θα πρέπει να χρησιμοποιηθεί ωςentry
πατέραςchunk
Παιδί ακόμαchunk
,CommonChunkPlugin
ενοποιημένη επεξεργασία ως μητρικήchunk
, σε ορισμένες περιπτώσεις έχει σημαντικό αρνητικό αντίκτυπο στην απόδοση.
Για το λόγο αυτό, πιο περίπλοκες δομές δεδομένων εισήχθησαν ειδικά μετά το Webpack 4—— ChunkGroup
Εξειδικεύεται στην υλοποίηση διαχείρισης και συνεργασίας αλυσίδας σχέσεωνSplitChunksPlugin
μπορεί να εφαρμοστεί πιο αποτελεσματικά και έξυπναΕυρετική υπεργολαβία.
Συνοπτικά, η φάση "Build" είναι υπεύθυνη για τη δημιουργία του ModuleGraph με βάση τη σχέση αναφοράς της ενότητας, η φάση "Encapsulation" είναι υπεύθυνη για τη δημιουργία μιας σειράς αντικειμένων με βάση το ModuleGraph και την οργάνωση των εξαρτήσεων μεταξύ των Chunks (ασύγχρονες αναφορές, χρόνος εκτέλεσης). ) στο αντικείμενο γραφήματος ChunkGraph - Chunk Dependency. Παρόμοια με το ModuleGraph, η εισαγωγή της δομής ChunkGraph μπορεί επίσης να αποσυνδέσει τη λογική διαχείρισης των εξαρτήσεων μεταξύ των Chunks, καθιστώντας τη συνολική αρχιτεκτονική λογική πιο λογική και ευκολότερη στην επέκταση.
Ωστόσο, αν και φαίνεται πολύ περίπλοκο, ο πιο σημαντικός στόχος του σταδίου "συσκευασίας" εξακολουθεί να είναι να καθοριστεί πόσα Chunks υπάρχουν και ποιες Ενότητες περιλαμβάνονται σε κάθε Chunk - αυτοί είναι οι βασικοί παράγοντες που επηρεάζουν πραγματικά το τελικό αποτέλεσμα συσκευασίας.
Για αυτό το σημείο, πρέπει να κατανοήσουμε τους τρεις ενσωματωμένους κανόνες υπεργολαβίας του Webpack5: Entry Chunk, Async Chunk και Runtime Chunk Αυτές είναι οι πιο πρωτότυπες λογικές υπεργολαβίας (π splitChunksPlugin) βασίζονται όλα σε αυτό, με τη βοήθεια του buildChunkGraph
Διάφορα άγκιστρα ενεργοποιήθηκαν αργότερα, περαιτέρω διαχωρισμός, συγχώνευση και βελτιστοποίηση της δομής Chunk για την επίτευξη διευρυμένων αποτελεσμάτων υπεργολαβίας.
νομίζω Chunk
Θα δημιουργηθεί και μόνο ένα αρχείο προϊόντος; Γιατί;mini-css-extract-plugin
、file-loader
Πώς υλοποιείται αυτός ο τύπος στοιχείου που μπορεί να γράψει πρόσθετα αρχεία στο κάτω μέρος;