Laravel-mix: copied svg asset broken

Created on 28 Jan 2017  路  28Comments  路  Source: JeffreyWay/laravel-mix

i'am using flag-icon-css, and loaded by mix, some of the svg assets copied by mix to public/fonts are broken, but when copied manuelly work.

This is my mix config:

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

mix.disableNotifications();

mix
    .js('resources/assets/js/welcome/welcome-vendor.js', 'public/js')
    .js('resources/assets/js/welcome/welcome.js', 'public/js')
    .sass('resources/assets/sass/welcome/welcome-vendor.scss', 'public/css')
    .sass('resources/assets/sass/welcome/welcome.scss', 'public/css')
    .sourceMaps()
    .version();

is there a way to tel me mix to not copy these dependencies, or to use a custom shell script to copy dependencies?

Thank you for mix.disableNotification() :)

Most helpful comment

Lmao here we go again. I have already made a issue about this previously but I guess we will just wait for more issues to coming flowing in. I find it absurd that all svg's are treated as fonts per default.

All 28 comments

I'd need to see the related CSS, but any url that is absolute (/svg/path.svg) won't be modified by Webpack.

This is the current mix configuration i'am using

mix.disableNotifications();

mix

    .js('resources/assets/js/channel-show/app.js',           'public/js/channel-show.js')
    .js('resources/assets/js/channel-show/vendor.js',        'public/js/channel-show-vendor.js')
    .js('resources/assets/js/channels-by-country/app.js',    'public/js/channels-by-country.js')
    .js('resources/assets/js/channels-by-country/vendor.js', 'public/js/channels-by-country-vendor.js')
    .js('resources/assets/js/embed/app.js',                  'public/js/embed.js')
    .js('resources/assets/js/embed/vendor.js',               'public/js/embed-vendor.js')
    .js('resources/assets/js/welcome/app.js',                'public/js/welcome.js')
    .js('resources/assets/js/welcome/vendor.js',             'public/js/welcome-vendor.js')

    .sass('resources/assets/sass/channel-show/app.scss',           'public/css/channel-show.css')
    .sass('resources/assets/sass/channel-show/vendor.scss',        'public/css/channel-show-vendor.css')
    .sass('resources/assets/sass/channels-by-country/app.scss',    'public/css/channels-by-country.css')
    .sass('resources/assets/sass/channels-by-country/vendor.scss', 'public/css/channels-by-country-vendor.css')
    .sass('resources/assets/sass/embed/app.scss',                  'public/css/embed.css')
    .sass('resources/assets/sass/embed/vendor.scss',               'public/css/embed-vendor.css')
    .sass('resources/assets/sass/welcome/app.scss',                'public/css/welcome.css')
    .sass('resources/assets/sass/welcome/vendor.scss',             'public/css/welcome-vendor.css')

    .sourceMaps()
    .version();

and this is the vendor sass file

@import 'node_modules/bootstrap/scss/bootstrap';
@import 'node_modules/font-awesome/scss/font-awesome';
@import 'node_modules/flag-icon-css/sass/flag-icon';

font-awesome assets are copied with no problem, but flag-icon assets, which is this one i'am using https://github.com/lipis/flag-icon-css, most of the copied svg files are broken, but when i copy them manualy (i wrote a small shell for this) they shows up with no problem.

If you need anything else to identify the problem, please let me know.

Maybe getting broken by svgo or something similar (that's my guess, but I could be completely wrong; does mix even use that? it shows up in node_modules).

I think it caused by flag-icon-css use same name for 1x1 and 4x3 asset filename.

I am having the same issue. Copied SVGs are broken. Here is my mix file:

mix.copy('node_modules/summernote/dist/font', 'public/fonts');
mix.copy('resources/assets/fonts/roboto', 'public/fonts');
mix.copy('node_modules/summernote/dist/summernote.min.js', 'public/js');
mix.sass('resources/assets/sass/app.scss', 'public/css');
mix.js('resources/assets/js/app.js', 'public/js');
mix.version();

Also: I am just compiling the sass for flag-icon-css, but for some reason all svgs are getting copied automatically to public/fonts? This wasn't the case with elixir.

@apocalyarts - Right, Webpack will automatically move any required fonts and update your stylesheets automatically.

If there's an issue here, I need someone to give me basic reproducible steps so that I can see the error. Thanks!

@JeffreyWay oh, it's just that mix assumes always the fonts folder, but in the case of flag-icon-css, the svg files are in a folder called flags. I would want that mix would respect that file structure / give an option to disable automatic copying, so I can do it manually with mix.copy() and but it in a different folder than public/fonts.

@apocalyarts that problem references #286, you can use my solution if that fits your environment (currently it only keeps the vendor name, not the full file structure, but I'll work on that tomorrow). I'll only be able to create a PR if #327 gets reviewed, as there would be a merge conflict between the two.

Same thing here, mix is wrongly copying all svgs to the fonts folder, which is not the case all times (not every scalable vector graphic is a font, some of them can be just images). A way to reproduce my error case:

webpack.mix.js (default):

let mix = require('laravel-mix');
mix
    .js('resources/assets/js/app.js', 'public/js')
    .sass('resources/assets/sass/app.scss', 'public/css')

app.scss:

.test1 {
    /* wrongly copies to /fonts/anything.svg, it should have copied to /images/ */
    background-image: url(../images/anything.svg);
}
.test2 {
    /* does not copy at all: */
    background-image: url(/images/anything.svg);
}

/* copies nicely to /fonts/: */
@font-face {
    font-family: 'My Font Family';
    src: url('../fonts/MyFontFamily.eot');
    src: local('Baskerville Old Face'), local('MyFontFamily'),
         url('../fonts/MyFontFamily.eot?#iefix') format('embedded-opentype'),
         url('../fonts/MyFontFamily.woff2') format('woff2'),
         url('../fonts/MyFontFamily.woff') format('woff'),
         url('../fonts/MyFontFamily.ttf') format('truetype'),
         url('../fonts/MyFontFamily.svg#MyFontFamily') format('svg');
    font-weight: normal;
    font-style: normal;
}

Lmao here we go again. I have already made a issue about this previously but I guess we will just wait for more issues to coming flowing in. I find it absurd that all svg's are treated as fonts per default.

Isn't this just simple changes on webpack.config.js? Like so (from line 162 to 206):

{
    test: /\.(png|jpe?g|gif|svg)$/, // add svg here
    exclude: /(fonts)/, // added
    loaders: [
        {
            loader: 'file-loader',
            options: {
                name: path => {
                    if (! /node_modules|bower_components/.test(path)) {
                        return 'images/[name].[ext]?[hash]';
                    }

                    return 'images/vendor/' + path
                        .replace(/\\/g, '/')
                        .replace(
                            /((.*(node_modules|bower_components))|images|image|img|assets)\//g, ''
                        ) + '?[hash]';
                },
                publicPath: Mix.options.resourceRoot
            }
        },
        {
            loader: 'img-loader',
            options: Mix.options.imgLoaderOptions
        }
    ]
},

{
    test: /\.(woff2?|ttf|eot|svg|otf)$/,
    loader: 'file-loader',
    exclude: /(images)/, // added
    options: {
        name: path => {
            if (! /node_modules|bower_components/.test(path)) {
                return 'fonts/[name].[ext]?[hash]';
            }

            return 'fonts/vendor/' + path
                .replace(/\\/g, '/')
                .replace(
                    /((.*(node_modules|bower_components))|fonts|font|assets)\//g, ''
                ) + '?[hash]';
        },
        publicPath: Mix.options.resourceRoot
    }
},

It is a simple fix and it should be simple to fix. This should be fixed here however and not force a user to create a custom webpack configuration file themselves based on nothing more than an wrong assumption on how people will use this.

Seems like an assumption has to be made one way or another. If it doesn't match our assumption, can't we just use mix.webpackConfig() and do whatever we want?

I think we van all agree that most people seem to use them as images instead of fonts especially judging by the amount of issues already raised about this so far.

But yes if you want to know the truth you should have a poll which I guess will turn out about 95-5.

@stephan-v I'm not suggesting to create a custom webpack config, I was just trying to help finding a way to fix it. =)

I'm bothered too by the default behavior of Laravel Mix with SVG : putting them all in a fonts directory.
I can't find a good way to handle this issue, using mix.webpackConfig and the "smart" merging of config file lead to more issues, disabling processCssUrls or using absolute path cut some useful features.

SVG is mainly an image type not a font, and by the way SVG fonts support is quite anecdotal and will tend to disappear : "Removed from SVG 2.0 and considered as a deprecated feature with support being removed from browsers." (http://caniuse.com/#feat=svg-fonts)...

@xsindesign well pointed. =)

So can we expect to see the default behaviour changed as @giovannipds has suggested?

It seems that starting with laravel-mix v1.4.3 we can manipulate the webpack config before its handed over for processing.

So in the meantime something like this is possible:

Mix.listen('configReady', (webpackConfig) => {

    // Add "svg" to image loader test
    let imageLoaderConfig = webpackConfig.module.rules.find(rule => String(rule.test) === String(/\.(png|jpe?g|gif)$/));

    imageLoaderConfig.test =  /\.(png|jpe?g|gif|svg)$/;
    imageLoaderConfig.exclude = /(fonts)/;

    // Exclude 'img' folder from font loader
    let fontLoaderConfig = webpackConfig.module.rules.find(rule => String(rule.test) === String(/\.(woff2?|ttf|eot|svg|otf)$/))

    fontLoaderConfig.exclude = /(assets\/img)/;

})

Or we could just not shoot ourselves in the foot and treat SVG's like images per default, since that is how the majority uses them.

I can't believe this is still even something that should be discussed but ok, that is the hazard you get when you let a single developer take a community hostage.

That's low. If having to add a few lines to your code to make a package work how you want, is holding you hostage, then maybe the package isn't for you. Just use webpack and then you can configure every single detail exactly how you want.

This is about common sense. Saying "the package isn't for you" is simply dismissive.

I have solved my problems and I am not here to argue about those, I am just sick and tired of seeing a community agreeing on a topic and not being heard.

But we all know what this boils down to. Jeffrey Way simply uses SVG's as fonts and therefore this will not be changed.

The suggestion goes beyond laravel mix. If you're using any library written by someone else, who pours their life into helping a community, and you feel like a hostage; run. Get as far away as possible.

Way to handle this.

Found a possible solution. Commented in the related issue #1231.

It is not a proper solution I am afraid.

@priithansen I'm running [email protected]. How exactly can I manipulate the webpack config before its handed over for processing?

Fixed in #1367.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mementoneli picture mementoneli  路  3Comments

rderimay picture rderimay  路  3Comments

dtheb picture dtheb  路  3Comments

RomainGoncalves picture RomainGoncalves  路  3Comments

mstralka picture mstralka  路  3Comments