Loading chunk error when importing conditional JS files to app.js - yarn build

Hi there,

I am trying to do conditional importing in the app.js file by doing the following for example:

if (document.querySelector('.js-nav-toggler')) {
  import(/* webpackChunkName: "nav" */ './components/nav')
}

This works fine when running yarn dev, but when I run yarn build I get into errors saying the following:

Uncaught (in promise) ChunkLoadError: Loading chunk 411 failed.
(error: http://undo-dev.local/nav.373c53.js)

I haven’t made any changes to the config, so not sure if I need to update anything as I just ran a clean install.

I have downloaded the latest version of Sage and using the latest version of Bud that came with it (v5.7.6).

Is there any documentation on conditional imports or can someone offer some advice?

Thanks in advance :smile:

Jack

Can anyone advise on this?

I can see the files are added to vendor, and the manifest.json is being updated, but when I load the frontend it’s still erroring.

Thanks,

Jack

From what I can tell the path to the chunk isn’t written correctly, though I’m not too sure how to remedy it. Since bud rewrites requests to the chunks when using the dev server it doesn’t matter that the chunks are requested from the root url, in your case http://undo-dev.local/, but when built and run from production the chunk needs to be referenced relative to the theme/public folder, which it obviously isn’t.

You may be able to set __webpack_public_path__ using bud.setPublicPath | bud.js where it would look something like this I believe

module.exports = (app) => {
  app
    .setPublicPath('/wp-content/themes/<theme-name>/public')
  ...

If that doesn’t work you might be able to find more info here Public Path | webpack

I know when I used lazy loading on a few Shopify sites I’ve done as long as I set __webpack_public_path__ before the import() it worked fine like so

script_variables.liquid

window.__webpack_public_path__ = '{{- assetsPath -}}';

module.js

__webpack_public_path__  = window.__webpack_public_path__;
const cartIndicatorModule = () => import(
  /* webpackPrefetch: true */
  /* webpackChunkName: "app-cart-indicator" */
  '../apps/cart-indicator'
).then((module) => {
  ...
});

Hi zzzap,

This has got the JS working now thank you!! Life saver.

However now my image files path is doubling up to look like http://undo-dev.local/wp-content/themes/undo/public/wp-content/themes/undo/public/images/footer/terra-carta.svg

I am using blade icons so can resort to using this for my icons for now until I find a solution for assets.

If you have any idea on that it would be a great help! If not no worries.

Thanks again!

Jack

So I just noticed in the budj.s blog here that setPublicPath is deprecated when using Sage. Searched around on here a bit more and found this post that gives a couple options.

I think option #2 is cleaner and would do something like this, note the following is untested

bud.config.js

/**
 * @typedef {import('@roots/bud').Bud} bud
 *
 * @param {bud} app
 */
module.exports = (app) => {
  app
    .define({
     // Uses webpack define under the hood, https://webpack.js.org/plugins/define-plugin/
      PUBLIC_PATH: JSON.stringify('/wp-content/themes/<theme name>/public'),
    })

and then in a script that you can import anywhere you need to use dynamic imports

resources/scripts/public-path.js

// Required for lazy-loading with Webpack.
__webpack_public_path__ = PUBLIC_PATH;

resources/scripts/app.js

import {domReady} from '@roots/sage/client';
import './public-path.js'

const loadCartIndicatorModule = async () =>
  await import(
    /* webpackPrefetch: true */
    /* webpackChunkName: "app-cart-indicator" */
    './app/cart-indicator'
  ).then(({default: module}) => module);

const main = (error) => {
  if (error) {
    console.error(error);
  }

  if(document.querySelector('.has-cart') {
     loadCartIndicatorModule().then((cartModule) => {
        ...
     });
  }
  ...
}

domReady(main);

@zzzap you’re amazing thank you so much!

I can confirm this put me on the right track and managed to get this working:

.entry({
  app: {
    import: ['@scripts/app', '@styles/app'],
    publicPath: '/wp-content/themes/undo/public/'
  },
  editor: ['@scripts/editor', '@styles/editor'],
})

Works in both dev and prod mode :ok_hand:

Once again, thank you for your help!

Jack

PS. I do feel this should be unneccessary though! Shouldn’t it really work out of the box?

2 Likes

Automatic public path works in dev and production mode without defining it with webpack magic variables or in the entry object (as of 5.7.6, iirc).

Getting WordPress and Webpack to use an automatic public path that worked for dev and production wasn’t as trivial as you’d think. In the end, we ended up getting bud and acorn to coordinate with one another using http headers when in dev and used an empty string in production (basically, same as webpack auto).

@roots/sage:

acorn: