Sage 10 + Bedrock | Image assets not found

Hi all,

We are working on a website which is running with Sage 10 and Bedrock.
Now we have the problem that the URL of the images in the assets folder are not working.

We did add the image netherlands.png in the folder web/app/themes/abs/resources/images/netherlands.png

Now we use the following code to get the image url @asset('images/netherlands.png').

On the page it returns as following url https://abs.test/app/themes/abs/public/images/netherlands.png but when we visit the url it is not working, it just returns to the homepage.

We are working with Laravel Valet as our local development stack.

Does anybody know why the images are not working? We did use Sage 10 alone without Bedrock without any issues.

Thanks for your time!

1 Like

I am having the same problem.

In the latest version:

    "@roots/bud": "^5.9",
    "@roots/bud-postcss": "^5.9",
    "@roots/bud-sass": "^5.9",
    "@roots/bud-tailwindcss": "^5.9",
    "@roots/sage": "^5.9"

If I add an image to: web/app/themes//resources/images

the image is not copied to the web/app/themes//public folder, and therefore a 404 is thrown once I call it

@asset('images/image.png')

in bud.config.js

    /**
     * These files should be processed as part of the build
     * even if they are not explicitly imported in application assets.
     */
    .assets('images')

If I manually copy the folder to the public directory, it works. Any help?

Waiting for the answer as I am also facing the same problem.

Same issue here. I noticed that my images are copied to the public/ instead of public/images/ directory.

"@roots/bud": "^5.8.7",
"@roots/bud-postcss": "^5.8.7",
"@roots/bud-sass": "^5.8.7",
"@roots/sage": "^5.8.7",
"foundation-sites": "^6.7.4"
1 Like

Same thing for me. I had to downgrade bud to 5.7.7 and then “yarn build” would spit out the nested folder structure under public

Unfortunately I am getting the same error. I had to downgrade to 5.7.7 too. It works.

"devDependencies": {
    "@roots/bud": "5.8.7",
    "@roots/bud-tailwindcss": "5.8.7",
    "@roots/sage": "5.8.7",
    "@shufo/prettier-plugin-blade": "^1.3.1",
    "browser-sync": "^2.27.9",
    "browser-sync-webpack-plugin": "^2.3.0",
    "prettier": "^2.6.2",
    "tailwindcss-debug-screens": "^2.2.1"
  },

I finally ended up changing my assets config in bud.config.js to the following

 .assets( {
        from: app.path( '@src/images' ),
        to: app.path( '@dist/images/[name].[contenthash][ext]' ),
      },
      {
        from: app.path( '@src/images/svg' ),
        to: app.path( '@dist/images/svg/[name].[contenthash][ext]' ),
      }, {
        from: app.path( '@src/fonts' ),
        to: app.path( '@dist/fonts/[name].[contenthash][ext]' ),
      } )

If this current behaviour with flattened file output turns out to be a feature and not a bug the above would be a future proof solution. (staying on bud v 5.8.7)

2 Likes

Follow up on this. It actually still compiles.

What happens to me is the following:

  "devDependencies": {
    "@roots/bud": "^5.8.7",
    "@roots/bud-postcss": "^5.8.7",
    "@roots/bud-sass": "^5.8.7",
    "@roots/bud-tailwindcss": "^5.8.7",
    "@roots/sage": "^5.8.7"
  }

When compiling I would get an error since there was no folder /images created within the public folder.

But I notice that the files are inside the public folder just not in a subfolder.

So if you are calling in the blade template like:

src="@asset('images/images.png')"

Just remove ‘images’ and it will work

src="@asset('images.png')"

Not 100% how it is going to work within subfolders with same names though.

1 Like

Don’t think this is approach scales. If you had images under resources/images and resources/images/maps and say there were two image files both called map.png in both of the directories. When you build, under public you’d end up having two distinct files map.[hash1].png and map.[hash2].png, which is all good, but in public/manifest.json you’d have entry only for one of them, the one from the subfolder.

So when you do @asset(‘map.png’) only the image from the subfolder will ever be shown. There is no way to reference the image from resources/images in this scenario.

Quite unexpected IMHO.

This drove me insane.

I spent 3 days trying to figure out what was wrong. I was pretty sure was my bad. I’m not new to WP development, and I the only reason I decide to start working with it again is Roots’s workflow. I however had to learn npm, yarn, Blade, gulp and all those ‘modern’ tools.

Turned out that, yes, the newest version of Bud flattens all resources on /public. It’s to early for me to make assumption if this is good or bad, but I share your same thoughts.

I don’t have a great grasp of Bud’s internals, so I can’t speak to the reasoning behind this decision or if there’s a simpler way to modify it, but the Bud docs mention a way to bypass the assets() API if you want:

// This doesn't appear to return a chainable object, so add it after your initial definition.
app.extensions.get('copy-webpack-plugin').setOption('patterns', [
  {
    from: app.path('@src/images'),
  },
]);

I tested this locally with a fresh Sage install, and it didn’t flatten assets into a single folder, i.e.:

resources/
  images/
    image-1.jpg
   subdir/
    image-2.jpg

Resulted in:

/public
  image-1.jpg
  /subdir
    image-2.jpg

If you wanted to dig into the reasons for this, the bud.assets code is here: bud/assets.method.ts at 9bd07900c5b98b00b835d53e1dcd4a17e6ee5c1b · roots/bud · GitHub

This provides some context for why webpack is (probably) flattening the dirs: GitHub - webpack-contrib/copy-webpack-plugin: Copy files and directories with webpack

4 Likes

UPDATE


It seems I was able to fix my issue. This is my updated bud.config.js file:

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

const bs = require('browser-sync-webpack-plugin')

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

    /**
     * These files should be processed as part of the build
     * even if they are not explicitly imported in application assets.
     */
    // .assets('images')
    .assets({
        from: app.path('@src/images'),
        to: app.path('@dist/images'),
      },
      {
        from: app.path('@src/fonts'),
        to: app.path('@dist/fonts'),
      })

    /**
     * These files will trigger a full page reload
     * when modified.
     */
    .watch('index.php', 'resources/views/**/*', 'app/**/*')

    /**
     * Target URL to be proxied by the dev server.
     *
     * This should be the URL you use to visit your local development server.
     */
    .proxy(app.env.get('WP_HOME'))

    .use({
      name: 'browser-sync-webpack-plugin',
      make: () => new bs({proxy: app.env.get('WP_HOME')}),
    })

    /**
     * Development URL to be used in the browser.
     */
    .serve({
      host: app.env.get('ENC_DEVELOPMENT_DOMAIN'),
      cert: app.env.get('ENC_DEVELOPMENT_SSL_CRT'),
      key: app.env.get('ENC_DEVELOPMENT_SSL_KEY'),
    });
};

@alwaysblank I am using bud 5.8.x and this is my whole bud.config.js file
I am missing something, because yours suggestion it is not working for me (it must be my fault).

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

const bs = require('browser-sync-webpack-plugin')

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

    /**
     * These files should be processed as part of the build
     * even if they are not explicitly imported in application assets.
     */
    .assets('images')

    /**
     * These files will trigger a full page reload
     * when modified.
     */
    .watch('index.php', 'resources/views/**/*', 'app/**/*')

    /**
     * Target URL to be proxied by the dev server.
     *
     * This should be the URL you use to visit your local development server.
     */
    .proxy(app.env.get('WP_HOME'))

    .use({
      name: 'browser-sync-webpack-plugin', make: () => new bs({proxy: app.env.get('WP_HOME')}),
    })

    /**
     * Development URL to be used in the browser.
     */
    .serve({
      host: app.env.get('ENC_DEVELOPMENT_DOMAIN'),
      cert: app.env.get('ENC_DEVELOPMENT_SSL_CRT'),
      key: app.env.get('ENC_DEVELOPMENT_SSL_KEY'),
    });

  // This doesn't appear to return a chainable object, so add it after your initial definition.
  app.extensions.get('copy-webpack-plugin').setOption('patterns', [
    {
      from: app.path('@src/images'),
    },
  ]);
};

Thank you

1 Like

You probably need to remove this:

1 Like

Thank you @alwaysblank. I fixed and updated my previous post.

Cheers