Bud - Upgrading to 5.2.0 causing problems

I updated the Bud version to 5.2.0 and it has caused some problems:

On the update notes, it is said that setPublicPath is deprecated and I removed it, but the URL of the assets is wrong now and they are not found and a lot ChunkLoadError errors appear.
If I add the setPublicPath, then it shows: TypeError: app.use() requires a middleware function.

If I remove my .use() configuration, there are no terminal errors, but still the JS files are not found. I see on the folder structure that they are inside a vendor folder(?).

This is my bud config:

const path = require('path')
require('dotenv').config({ path: path.resolve(__dirname, '../../../.env') })

const SVGSpritemapPlugin = require('svg-spritemap-webpack-plugin')

/**
 * @typedef {import('@roots/bud').Bud} Bud
 *
 * @param {Bud} config
 */

module.exports = (app) =>
  app
    /**
     * Application entrypoints`
     *
     * Paths are relative to your resources directory
     */
    .entry({
      app: ['scripts/app.js', 'styles/app.scss']
    })

    /**
     * These files should be processed as part of the build
     * even if they are not explicitly imported in application assets.
     */
    .assets([app.path('src', 'images')])
    .assets([app.path('src', 'fonts')])

    /**
     * These files will trigger a full page reload
     * when modified.
     */
    .watch([
      'tailwind.config.js',
      'resources/views/**/*.blade.php',
      'app/View/**/*.php'
    ])

    /**
     * Target URL to be proxied by the dev server.
     *
     * This is your local dev server.
     */
    .proxy(process.env.WP_HOME)

    .use(
      new SVGSpritemapPlugin('resources/sprite/*.svg', {
        output: {
          filename: 'spritesheet.svg',
          chunk: { keep: true },
          svgo: false
        }
      })
    )

I have no idea what to do in this case.

How exactly are they wrong?

  1. What is the URL of the asset now?
  2. What is the expected URL of the asset?

What are the exact errors?

:stop_sign: you already noticed this was deprecated — don’t re-add it :sweat_smile:

How did you update to Bud v5.2.0 in the first place? Did you wipe your node modules directory in the process?

Have you confirmed that your problems still exist on a clean installation?

Ok, I believe I can say that this is not a problem related to Bud 5.2.0.

When I run yarn build I get these problems too even in 5.1.0.

ChunkLoadError: Loading chunk 783 failed.
(error: https://my-site.test/e-boutique/bridal/shoes/jasmine-2/component-Header.152e59.js)
    at Object.i.f.j ((index):562:4487)
    at (index):562:2966
    at Array.reduce (<anonymous>)
    at i.e ((index):562:2931)
    at Array.map (<anonymous>)
    at o (app.e20c45.js:1:4016)
    at Object.importComponents (app.e20c45.js:1:3452)
    at Object.instanceComponent (app.e20c45.js:1:3285)
    at app.e20c45.js:1:3016
    at Array.forEach (<anonymous>) 'ChunkLoadError: Loading chunk 783 failed.\n(error: https://my-site.test/e-boutique/bridal/shoes/jasmine-2/component-Header.152e59.js)\n    at Object.i.f.j (https://my-site.test/e-boutique/bridal/shoes/jasmine-2/:562:4487)\n    at https://my-site.test/e-boutique/bridal/shoes/jasmine-2/:562:2966\n    at Array.reduce (<anonymous>)\n    at i.e (https://my-site.test/e-boutique/bridal/shoes/jasmine-2/:562:2931)\n    at Array.map (<anonymous>)\n    at o (https://my-site.test/app/themes/my-site/public/app.e20c45.js:1:4016)\n    at Object.importComponents (https://my-site.test/app/themes/my-site/public/app.e20c45.js:1:3452)\n    at Object.instanceComponent (https://my-site.test/app/themes/my-site/public/app.e20c45.js:1:3285)\n    at https://my-site.test/app/themes/my-site/public/app.e20c45.js:1:3016\n    at Array.forEach (<anonymous>)'

I guess this happens because it doesn’t find the component’s files.

I use the regenerator-runtime to load my components dynamically. So, I got a function like this:

async importComponents(componentName) {
    return await import(
      /* webpackChunkName:`component-[request]` */ /* webpackMode: "lazy" */ `./components/${componentName}`
    )
  }

On the DevTools → Sources, I see that for some reason there are two app JS files: One in the public folder, the other in the public/vendor folder. I don’t get this.

This is the entrypoints.json:

{
  "app": {
    "js": [
      "runtime.7743d4.js",
      "vendor/app.d5ad86.js",
      "app.e20c45.js"
    ],
    "css": [
      "app.d2fc14.css"
    ],
    "dependencies": []
  }
}

And a screenshot of the public folder:

why we split your application into two files

On the DevTools → Sources, I see that for some reason there are two app JS files: One in the public folder, the other in the public/vendor folder. I don’t get this.

if you don’t want to vendor your scripts you can disable splitChunks with:

bud.splitChunks(false)

I don’t recommend this:

  • the browser caches files based on name
  • you probably release versions of your sage theme more than your production dependencies change
  • if you have a single app.[hash].js it means that every time you change your application code you are requiring users to download the entire app, including all the dependencies, again.
  • instead, there is a separate vendor/app.[hash].js file emitted to hold your dependencies. this file will not change unless you update your dependencies.
  • by separating them the user only has to download the application code and can use the dependencies from their cache.

you can read more here:

Your build failure

I can reproduce it. But, I can also fix it very easily. This is not a problem with bud.

I guess this happens because it doesn’t find the component’s files.

it is. Because your public path isn’t set. Because there is no dotenv.

You are relying on the package dotenv to just be present in your node_modules and it isn’t. You should not just be relying on common dependencies like dotenv or lodash to be present in your environment, although it is common to do that. In general, if you require or import a module directly, you should install it or have a dependable way to resolve it otherwise.

two choices. you can, as normal, install dotenv:

npm install dotenv --dev

Or, you can use the one that comes bundled in @roots/bud-support:

const {env} = require('@roots/bud-support')

We bundle this dependency (and many others) into a single package to keep your node_modules lightweight. This is an (unpublicized) feature and should be considered an internal API. But, you can probably rely on it for stuff like lodash & dotenv.

bud should give you better error messaging (and crash) when you make errors like this. it will do so in 5.3.0.

Dynamic imports

I don’t think you need to do anything with regenerator-runtime. You probably don’t need any of those legacy webpack magic comments.

https://webpack.js.org/guides/code-splitting#dynamic-imports

If you want to use lazy mode you can remove the magic comment and enable it like so:

.experiments('lazyCompilation', {
      // disable lazy compilation for dynamic imports
      imports: false,

      // disable lazy compilation for entries
      entries: false,
      
      // do not lazily compile moduleB
      test: (module) => !/moduleB/.test(module.nameForCondition()),
    })

https://webpack.js.org/configuration/experiments/#experimentslazycompilation

2 Likes

Thank you for your detailed answer, but I’m afraid it didn’t help me :confused:

Yeap, I don’t want to disable splitChunks

But it actually is. I do have installed the dotenv package Nevertheless, I don’t understand your intention in this paragraph regarding the problem.

I have added the .experiments('lazyCompilation) and removed the comments, but I still get the same result. I even tried it in a new Sage 10 installation and it still occurs. The chunks loading is failing. The URL is wrong. I’m lost.

Edit: Here’s a repo: https://github.com/erip2/module-lazyload with the minimal setup on a new theme.

I opened a PR on your repro that fixes the issue.

You removed the boilerplate from @scripts/components but you didn’t remove the code that imports it.

Thank you again for your answer. I appreciate you taking your time for this.

This is not a solution, unfortunately :sweat:

I don’t think editor.js has anything to do with my problem. My problem is that the files inside the components folder don’t get loaded. I’m not using and I have no intention to use editor.js.

The whole logic of my structure lies in app.js.

@erip2, it seems there are two separate issues in the app code you provided.

The first was that it wouldn’t compile because of a bad import in editor.js. The bad import was the cause of the compilation failure and with my fix (removing the import) it compiles again in CI and locally.

I looked back into it when you said you were still having problems and ultimately could reproduce your browser error.

The issue in the application code is that you are dynamically loading modules and so you need to dynamically set the public path.

I merged an addition to my earlier PR that includes an application level fix for this. The code works in the browser now.

Ultimately, you need to do two things:

  1. This is kind of optional but recommended. Define the publicPath in your bud.config.js file. Make sure to escape the value. I did it with bud.env but you can use env or just add it as a string. Whatever works.
    /**
      * Define the public path for dynamically imported assets.
      *
      * I am defining it an .env file and accessing it with `bud.env`.
      */
     .define({
       ASSET_PATH: JSON.stringify(app.env.get('ASSET_PATH')),
     })
  1. Set __webpack_public_path__:
// eslint-disable-next-line no-undef
__webpack_public_path__ = ASSET_PATH;

I did this in a separate module which was imported to the top of app.js intentionally since it works for literally all setups (newer esmodule imports will break if you just add it at the top of the entrypoint).

see bud documentation on bud.define:

and the documentation from webpack on publicPath:

Thanks so much. Can confirm that this works on dev & build.

Also, updated to 5.2.0 on my current project and it’s going fine :smiley:

1 Like