Final Edit
La résolution de cette question est que c'est impossible. Bien que la réponse ci-dessous donne de bonnes informations.
Considérons le code ci-dessous, à partir de contacts.js
. Il s'agit d'un module chargé dynamiquement, chargé à la demande avec System.import
ailleurs dans le code.
Si SharedUtil1
est également utilisé dans d'autres modules qui sont également chargé dynamiquement avec System.import
, comment puis-je avoir SharedUtility1
exclu de tous de ces modules, et chargé uniquement à la demande _ {première fois c'est nécessaire?
Un System.import
de niveau supérieur de SharedUtil1
ne fonctionnera pas, car mon exportation en dépend: les exportations ne peuvent être placées qu'au niveau supérieur du code d'un module, et non dans aucun type de rappel.
Est-ce possible avec Webpack? Je suis sur la version 2.0.7 beta.
import SharedUtil1 from '../../SharedUtilities/SharedUtility1';
class Contacts{
constructor(data){
this.data = data;
this.sharedUtil1 = new SharedUtil1();
}
}
export default Contacts;
UPDATE 1
Je pensais que le bundle loader était ce que je voulais, mais non, cela transforme votre module importé en une fonction différente que vous appelez avec un rappel pour accéder au module réel, une fois le chargement asynchrone terminé. Cela signifie que vous ne pouvez pas charger le module X de manière transparente de manière asynchrone sans apporter de modifications majeures à votre code, sans parler du fait que vous êtes de retour au problème décrit à l'origine, si votre module de niveau supérieur dépend du maintenant-asynchrone dépendance dépendante, il n’existe aucun moyen de l’exporter, car les exportations doivent se situer au plus haut niveau.
Dans Webpack, n'y a-t-il aucun moyen d'indiquer que la dépendance X doit être chargée à la demande, si nécessaire, et que les modules importés l'important de manière à attendre de manière transparente le processus d'importation? Je penserais que ce cas d'utilisation serait un sine qua non pour toute application distante, donc je dois penser qu'il me manque quelque chose.
UPDATE 2
Selon la réponse de Peter, j'ai essayé de faire fonctionner la déduplication, car le plugin commonChunk concerne le partage de code entre les points finaux, comme il l'a mentionné, et puisque require.ensure
place le code chargé dans un rappel, vous évitant ainsi que ES6 export
ne contienne du code qui en dépend. .
En ce qui concerne la déduplication, contacts.js
et tasks.js
chargent le même sharedUtil comme suit
import SharedUtil1 from '../../sharedUtilities/sharedUtility1';
J'ai essayé de lancer webpack en tant que
webpack --optimize-dedupe
et aussi en ajoutant
plugins: [
new webpack.optimize.DedupePlugin()
]
à webpack.config. Dans les deux cas, le code sharedUtil est toujours placé dans les ensembles de contacts et de tâches.
Après avoir lu votre blog, j'ai enfin compris votre intention. J'ai été un peu confus par le mot "Dépendances de premier niveau".
Vous avez deux modules (async-a
et async-b
) qui sont chargés à la demande de n'importe où (ici un module main
) et qui ont tous deux une référence sur un module partagé (shared
).
- - -> on-demand-loading (i. e. System.import)
---> sync loading (i. e. import)
main - - -> async-a ---> shared
main - - -> async-b ---> shared
Par défaut, Webpack crée un arbre de morceaux comme ceci:
---> chunk uses other chunk (child-parent-relationship)
entry chunk [main] ---> on-demand chunk 1 [async-a, shared]
entry chunk [main] ---> on-demand chunk 2 [async-b, shared]
Cela convient si shared
<async-a/b
ou si la probabilité que async-a
et async-b
soient utilisés par le même utilisateur est faible. C'est la valeur par défaut parce que ce sont les comportements les plus simples et probablement ce à quoi vous vous attendriez: un System.import
=> un morceau. À mon avis, c'est aussi le cas le plus courant.
Mais si shared
> = async-a/b
et que la probabilité que async-a
et async-b
soient chargés par l'utilisateur soit élevée, il existe une option de segmentation plus efficace: (un peu difficile à visualiser):
entry chunk [main] ---> on-demand chunk 1 [async-a]
entry chunk [main] ---> on-demand chunk 2 [async-b]
entry chunk [main] ---> on-demand chunk 3 [shared]
When main requests async-a: chunk 1 and 3 is loaded in parallel
When main requests async-b: chunk 2 and 3 is loaded in parallel
(chunks are only loaded if not already loaded)
Ce n'est pas le comportement par défaut, mais il existe un plugin pour l'archiver: La CommonChunkPlugin
en mode async. Il trouve les modules communs/partagés dans un tas de morceaux et crée un nouveau morceaux qui inclut les modules partagés. En mode asynchrone, il charge le nouveau bloc en parallèle aux blocs d'origine (mais maintenant plus petits).
new CommonsChunkPlugin({
async: true
})
// This does: (pseudo code)
foreach chunk in application.chunks
var shared = getSharedModules(chunks: chunk.children, options)
if shared.length > 0
var commonsChunk = new Chunk(modules: shared, parent: chunk)
foreach child in chunk.children where child.containsAny(shared)
child.removeAll(shared)
foreach dependency in chunk.getAsyncDepenendenciesTo(child)
dependeny.addChunk(commonsChunk)
Gardez à l'esprit que CommonsChunkPlugin a une option minChunks
pour définir le moment où un module est threadé en tant que shared
(n'hésitez pas à fournir une fonction personnalisée pour sélectionner les modules).
Voici un exemple qui explique la configuration et la sortie en détail: https://github.com/webpack/webpack/tree/master/examples/extra-async-chunk
Et un autre avec plus de configuration: https://github.com/webpack/webpack/tree/master/examples/extra-async-chunk-advanced
System.import
est obsolète dans Webpack. Webpack préfère maintenant import()
qui nécessite un polyfill pour les promesses.