Klathmon / imagemin-webpack-plugin

Plugin to compress images with imagemin
MIT License
685 stars 53 forks source link

Error: Premature end of JPEG file #82

Closed loooping-old closed 5 years ago

loooping-old commented 5 years ago

In my build I had the error:

I noticed that the error only occurs in a folder that is more than 1GB

How to skip corrupted files?

Error: Premature end of JPEG file

    at Promise.all.then.arr (/Users/pablo/Workflow/PHP/lamp/www/thesite/node_modules/execa/index.js:231:11)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:182:7)

My Webpack config:

const path = require( 'path' );
const ExtractTextPlugin = require( 'extract-text-webpack-plugin' );
const StyleLintPlugin = require('stylelint-webpack-plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
const ImageminPlugin = require('imagemin-webpack-plugin').default;
const CopyPlugin = require('copy-webpack-plugin');

const settings = {
    // The BrowserSync hostname
    host: 'localhost',
    // The port to run BrowserSync's server on
    port: 3000,

  files: [
    './template/**/*.php',
    './content/**/*.php'
  ],

    // A target to proxy all BrowserSync requests to.
    // This can be a local web server, Vagrant or a docker container.
    proxy: 'http://localhost/thesite',

    // If you have your Site URL for WordPress set to anything else other than the proxy address,
    // we need to override all URL. In this example I am overriding my site at http://training-ground.local
    urlOverride: /training-ground\.local/g
};

module.exports = {
    entry: './assets/js/main.js',
    output: {
    filename: 'main.js',
    path: __dirname + "/dist/js"
    },
    devtool: 'source-map',
    module: {
        loaders: [
            // Setup ESLint loader for JS.
            {
                enforce: 'pre',
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'eslint-loader',
                options: {
                    emitWarning: true,
                }
            },
            // Run JS through Babel Loader before bundling it to `scripts.js`
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader'
            },
            // Run Sass through loaders before bundling into `style.css`
            {
                test: /\.scss$/,
                enforce: 'pre',
                loader: ExtractTextPlugin.extract( [
                    {
                        loader: 'css-loader',
                        options: {
                            minimize: true,
                            sourceMap: true
                        }
                    },
                    {
                        loader: 'sass-loader'
                    }
                ] )
      },
      {
        test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 80000,
              mimetype: "application/font-woff",
              outputPath: "../fonts"
            }
          }
        ]
      },
      {
        test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        use: [
          {
            loader: "file-loader"
          }
        ]
      },
      { 
        test: /\.(jpe?g|png|gif|svg)$/i,
        loader: "url-loader" 
      }
        ]
    },
    plugins: [
        new ExtractTextPlugin( {
            filename: '../css/main.css'
        } ),
        new StyleLintPlugin({ syntax: 'scss' }),
        new UglifyJSPlugin({
      uglifyOptions: {
        mangle: {
          // Skip mangling these
          except: ['$super', '$', 'exports', 'require']
        },
        sourceMap: true
      }
    }),
        new BrowserSyncPlugin({
            host: settings.host,
      port: settings.port,
      files: settings.files,
            proxy: settings.proxy,
            rewriteRules: [
                {
                    match: settings.urlOverride,
                    fn: function (req, res, match) {
                        return settings.host + ':' + settings.port;
                    }
                }
            ]
    }),
    new CopyPlugin([{
      from: './assets/images/',
      to: '../images/'
    }]),
    new ImageminPlugin({ test: /\.(jpe?g|png|gif|svg)$/i })
    ]
}
Klathmon commented 5 years ago

Replace the ImageminPlugin part of your webpack config with this below:

new ImageminPlugin({
  maxConcurrency: 1,
  test: function (filename) { 
    console.log('Attempting to compress "' + filename + '"...')
    return (/\.(jpe?g|png|gif|svg)$/i).test(filename)
  }
})

When you run that, it should console.log each image that it is minifying as it minifies it. (it will take much longer because I set maxConcurrency to 1, but that is just for this test)

Then can you post the image that it logs right before failing so I can see it?

If it's really just a corrupted JPEG image, then this plugin won't give you any easy way to stop that right now. I might be able to make a change that catches errors like that and just puts the original image through, but I won't have time to do that for a little bit. (if you are willing, I'd gladly accept a PR to this plugin that does that!)

You might also be able to use copy-webpack-plugin's transform property to check that the JPEG is valid, and try to either fix or remove any broken/corrupted images before they get to this plugin.