web-dev-qa-db-fra.com

ES6 Dynamic Imports avec Webpack et Babel

J'utilise Webpack pour mon projet ES6 JS et ça va bien jusqu'à ce que je commence à jouer avec les importations dynamiques.

Qu'est-ce que j'avais qui a fonctionné (router.js):

import { navigo } from "Navigo"; // router
import { clients } from "Controllers/clients.js";

const navigo = new Navigo();

navigo_router.on({
  '/clients': () => {
    clients.init();
  }
});

Mais plus je rajoute de pages/de routes, plus d’importations s’empilent dans la tête du module. Ceci est une application relativement grande et j'ai beaucoup de pages/itinéraires à ajouter et j'ai donc besoin de les charger dynamiquement pour réduire la taille du chargement initial de la page.

Ainsi, en suivant la documentation de Webpack sur les importations dynamiques , j’ai essayé ce qui suit pour charger le module de contrôleur uniquement lorsque la route relative est appelée:

import { navigo } from "Navigo"; // router

const navigo = new Navigo();

navigo_router.on({
  '/clients': () => {
    import("Controllers/clients.js").then((clients) => {
      clients.init();
    });
  }
});

Mais enregistrer cela dans mon éditeur a entraîné une erreur de transposition de Babel; SyntaxError: 'import' et 'export' peuvent uniquement apparaître au niveau supérieur, et clients.init() n'est pas appelé lors du test dans le navigateur.

Après un peu de lecture, j'ai découvert qu'il me fallait un plugin Babel pour transpiler le import() dynamique en require.ensure. J'ai donc installé le plugin en utilisant la commande suivante:

npm install babel-plugin-dynamic-import-webpack --save-dev

Et déclaré le plugin dans mon fichier babel.rc

{ "plugins": ["dynamic-import-webpack"] }

Après l’installation du plugin, l’erreur de transpiling a disparu et la vérification de mon code transpilé, j’ai constaté que le import()s dynamique avait en fait été changé en require.ensure comme prévu. Mais maintenant, je reçois les erreurs de navigateur suivantes lors des tests:

Error: Loading chunk 0 failed.
Stack trace:
u@https://<mydomain.com>/js/app.bundle.js:1:871
SyntaxError: expected expression, got '<' 0.app.bundle.js:1
Error: Loading chunk 0 failed.

Je ne comprenais pas pourquoi il faisait référence à 0.app.bundle.js avec le préfixe 0.. J'ai donc vérifié mon dossier output/dist et j'ai maintenant un nouveau fichier appelé 0.app.bundle.js:

0.app.bundle.js      1,962bytes
app.bundle.js        110,656bytes

J'imagine que ce nouveau fichier fourni est le module importé dynamiquement, clients.js.

J'ai seulement ajouté une importation dynamique à cette route et laissé toutes les autres comme elles étaient. Ainsi, pendant les tests, je peux voir tous les itinéraires, à l'exception de celui /clients qui renvoie maintenant les erreurs ci-dessus.

Je suis totalement perdu à ce stade et espère que quelqu'un pourra m'aider. Passe-moi par-dessus la ligne d'arrivée. Qu'est-ce que ce nouveau fichier 0.app.bundle.js et comment suis-je censé l'utiliser/l'inclure dans mon application?

J'espère que je me suis expliqué assez clairement et j'attends vos réponses avec impatience.

7
Martin James

J'ai finalement réussi à résoudre mon propre problème, alors je vais partager ce que j'ai découvert dans une réponse.

La raison pour laquelle le fichier de bloc n'était pas chargé était parce que Webpack le cherchait dans le mauvais répertoire. J'ai remarqué dans l'onglet Réseau de ma console de développeur que le fichier/module de morceau était appelé depuis mon répertoire racine / et non dans le répertoire /js auquel il appartient.

Conformément à la documentation de Webpack, j'ai ajouté les éléments suivants à mon fichier de configuration Webpack:

output: {
  path: path.resolve(__dirname, 'dist/js'),
  publicPath: "/js/", //<---------------- added this
  filename: 'app.bundle.js'
},

D'après ce que j'ai compris, path est destiné aux modules statiques de Webpack et publicPath à des modules dynamiques.

Cela a permis de charger correctement le bloc, mais j'avais également d'autres problèmes à traiter, car client.init() n'était pas appelé et a généré l'erreur suivante:

TypeError: e.init is not a function

Pour résoudre ce problème, j'ai également dû changer:

import("Controllers/clients.js").then((clients) => {
  clients.init();
});

À:

import("Controllers/clients.js").then(({clients}) => {
  clients.init();
});

Notez les accolades dans le paramètre de fonction de flèche.

J'espère que cela aide quelqu'un d'autre.

3
Martin James

Pour le débogage, vous devez faire

import("Controllers/clients.js").then((clients) => {
    console.log(clients);
});

peut-être en train de travailler 

import("Controllers/clients.js").then((clients) => {
    clients.default.init();
});
0
Igor Ognichenko