georgeboot's avatar

Vapor ASSET_URL and images in Vue

I am trying to deploy an Inertia app to Vapor. I followed the documentation from Vapor on how to handle code splitting.

My javascript code works fine, webpack correctly sets the output directory and assetUrl.

However, in my Vue files, I do have some <img> tags linking to local files. Webpack automatically extracts them and uploads them the the cdn. However, webpack does not update the src of these images.

How can I get webpack to do that?

0 likes
9 replies
georgeboot's avatar

Nothing code specific, but here you go:

// resources/js/Pages/Homepage.vue

<template>
    <div>
        <img src="../../images/logo.jpg" />
    </div>
</template>

<script>

export default {
    name: 'Homepage'
}

</script>

Webpack automatically copies the logo.jpg from the images directory to the public/images folder. Vapor picks this up and uploads the asset to s3.

However, the img src is never updated to the new s3 url, like the js files are.

My mix file:

const mix = require('laravel-mix');

require('laravel-mix-tailwind');
require('laravel-mix-purgecss');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.postCss('resources/css/app.css', 'public/css')
    .tailwind('./tailwind.config.js');

mix.js('resources/js/app.js', 'public/js')
    .webpackConfig({
        output: { chunkFilename: 'js/[name].js?id=[chunkhash]' },
        resolve: {
            alias: {
                'vue$': 'vue/dist/vue.runtime.esm.js',
                '@': path.resolve('resources/js'),
            },
        },
    })
    .babelConfig({
        plugins: ['@babel/plugin-syntax-dynamic-import']
    })

if (mix.inProduction()) {
    const ASSET_URL = process.env.ASSET_URL + "/";

    mix.webpackConfig(webpack => {
        return {
            plugins: [
                new webpack.DefinePlugin({
                    "process.env.ASSET_PATH": JSON.stringify(ASSET_URL)
                })
            ],
            output: {
                publicPath: ASSET_URL
            }
        };
    });

    mix.version();
    mix.purgeCss({
        whitelistPatterns: [],
        whitelistPatternsChildren: [],
    });
}

georgeboot's avatar

My first assumption was that the two webpackConfigs were overwriting each other, but that is not the case. I verified it like so:

const mix = require('laravel-mix');

require('laravel-mix-tailwind');

const webpackConfig = webpack => {
    const config = {
        resolve: {
            alias: {
                'vue$': 'vue/dist/vue.runtime.esm.js',
                '@': path.resolve('resources/js'),
            },
        },
        output: {
            chunkFilename: 'js/[name].js?id=[chunkhash]',
        }
    }

    if (mix.inProduction()) {
        const ASSET_URL = process.env.ASSET_URL + "/";

        config.plugins = [
            new webpack.DefinePlugin({
                "process.env.ASSET_PATH": JSON.stringify(ASSET_URL)
            })
        ]

        config.output.publicPath = ASSET_URL
    }

    return config
}

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.postCss('resources/css/app.css', 'public/css');
mix.js('resources/js/app.js', 'public/js');

// css configs
mix.tailwind('./tailwind.config.js');

// js configs
mix.webpackConfig(webpackConfig);
mix.babelConfig({
    plugins: ['@babel/plugin-syntax-dynamic-import']
});

themsaid's avatar

I don't know if this can be done via webpack, you're referencing your images using a relative path. I don't think webpack is able to convert this to use the ASSET_URL out of the box.

1 like
georgeboot's avatar

@themsaid What part of Laravel mix converts that relative path to an absolute path and flags that image to be copied to the public dir?

Would say that it should be possible to prefix that value with an asset helper.

@wheeler thanks for that! Works for absolute paths, but not when referencing the file relatively. Will have to update a bunch of them, but I guess that is not the biggest problem.

georgeboot's avatar

I was able to fix it by adding:

mix.setResourceRoot(ASSET_URL)

to my webpack.mix.js, in addition to the other lines Vapor specifies in the docs.

@themsaid shouldn't this be added to the Vapor docs?

aligajani's avatar

@georgeboot How does that fix it for assets referenced inside .vue files? It didn’t work for me. I am picking up the ASSET_URL from index.blade.php , using it in a method as a global mixin called CDN() and using that in my .vue files instead. Works but surely there’s a better way.

60days's avatar

Hi @aligajani - did you find a cleaner way of achieving this? I'm about to start building the frontend of a Vapor project I've been working on, and I'm looking out for any pitfalls/lessons-learned before I jump in.

Please or to participate in this conversation.