web-dev-qa-db-fra.com

Webpack 2 - Fragmentation du code par les dépendances

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 SharedUtility1exclu 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.

16
Adam Rackis

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

15
Tobias K.

Selon le créateur de Webpack, c'est impossible. Clair et simple. Voir la réponse de Peter pour de nombreuses autres informations utiles concernant Webpack et ES6.

L'image collée était le résultat d'un malentendu. Voir la réponse du même utilisateur ci-dessus. 

 enter image description here

1
Adam Rackis

System.import est obsolète dans Webpack. Webpack préfère maintenant import() qui nécessite un polyfill pour les promesses.

Fractionnement du code - Utilisation de import ()

0
Josh English