Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ES6 Dynamic Imports using Webpack and Babel

I've been using Webpack for my ES6 JS project and has been going well until I started to play with dynamic imports.

What I had that worked (router.js):

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

const navigo = new Navigo();

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

But the more pages/routes I add, the more imports get stacked up in the head of the module. This is a relatively large app and I have a lot of pages/routes to add and therefore I need to load them dynamically to reduce the size of the initial page load.

So, following Webpack's documentation for dynamic imports, I tried the following which loads the controller module only when the relative route is called:

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

const navigo = new Navigo();

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

But saving this in my editor resulted in a Babel transpiling error; SyntaxError: 'import' and 'export' may only appear at the top level, and clients.init() is not being called when tested in browser.

After a bit of reading, I discovered I needed a Babel plugin to transpile dynamic import() to require.ensure. So, I installed the plugin using the following command:

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

And declared the plugin in my babel.rc file

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

After installing the plugin, the transpiling error disappeared and checking my transpiled code I found that the dynamic import()s has in fact been changed to require.ensure as expected. But now I get the following browser errors when testing:

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.

I didn't understand why it was referencing 0.app.bundle.js with the 0. prefix, so I checked my output/dist folder and I now have a new file in there called 0.app.bundle.js:

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

I imagine this new bundled file is the dynamically imported module, clients.js.

I only added dynamic importing to that one route and have left all the other routes as they were. So, during testing, I can view all routes except that one /clients route that now throws the above errors.

I'm totally lost at this point and hoped somebody could help push me over the finish line. What is this new file 0.app.bundle.js and how am I supposed to be using it/including it in my application?

I hope I've explained myself clearly enough and look forward to any responses.

like image 415
Martin James Avatar asked Feb 16 '18 13:02

Martin James


1 Answers

I managed to fix my own problem in the end, so I will share what I discovered in an answer.

The reason the chunk file wasn't loading was because Webpack was looking in the wrong directory for it. I noticed in the Network tab of my developer console that the the chunk file/module was being called from my root directory / and not in /js directory where it belongs.

As per Webpack's documentation, I added the following to my Webpack config file:

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

From what I understand, path is for Webpack's static modules and publicPath is for dynamic modules.

This made the chunk load correctly but I also had further issues to deal with, as client.init() wasn't being called and yielded the following error:

TypeError: e.init is not a function

To fix this, I also had to change:

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

To:

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

Note the curly braces in the arrow function parameter.

I hope this helps somebody else.

like image 65
Martin James Avatar answered Sep 20 '22 13:09

Martin James