Klathmon / imagemin-webpack-plugin

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

Imagemin miss out compress .png that generate by spritesmith #83

Closed majaclay closed 5 years ago

majaclay commented 5 years ago

My current project do use CopyWebpackPlugin and Spritesmith. Deal to spritesheet from spritesmith was not compress and i facing file size issue right now. I decided to use imagemin to compress the spritesheet generated by spritesmith but fail. Imagemin work fine for my other png file, even after copywebpack. I try to use external image and direct point to the spritesheet .png but also fail to compress it.

Can anyone help?

Klathmon commented 5 years ago

I need a few things to help you:

  1. Can you upload the sprite that spritesmith is generating for you so I can see it? It doesn't need to be public, you can email the image to me at gregbenner1@gmail.com if you would prefer.

  2. Can you post your webpack config that you are using?

  3. When you say it "fails" what do you mean? Can you describe in more detail what happens when it fails? If it is displaying any error messages, can you copy them here so I can see them?

majaclay commented 5 years ago
const path = require('path');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const VersionFile = require('webpack-version-file');
const GitRevisionPlugin = require('git-revision-webpack-plugin');
const gitRevisionPlugin = new GitRevisionPlugin();
const SpritesmithPlugin = require('webpack-spritesmith');
const ImageminPlugin = require('imagemin-webpack-plugin').default;

module.exports = (env, argv) => {

    const gameName = argv.game;
    if (!gameName) {
        throw new Error('`game` is not provided');
    }

    const environment = env.environment;
    const gameRoot = `./src/${gameName}`;
    const coreRoot = `./core`;
    const environmentFile = `environments/environment.${environment}.ts`;
    const entry = `${gameRoot}/index.js`;

    return {
        entry: entry,
        output: {
            filename: 'bundle.[chunkhash].js',
            path: path.resolve(__dirname, 'dist')
        },
        devServer: {
            contentBase: './dist'
        },
        module: {
            rules: [
                {
                    test: /\.css$/,
                    use: ['style-loader', 'css-loader']
                },
                {
                    test: /\.(jpe?g|png|gif|svg)$/i,
                    loader: "file-loader?name=[name].[ext]"
                },
                {
                    test: /\.tsx?$/,
                    loaders: [
                        'babel-loader',
                        'ts-loader',
                        {
                            loader: 'string-replace-loader',
                            options: {
                                search: '__GAME_NAME__',
                                replace: gameName,
                            }
                        }
                    ],
                    exclude: /node_modules/
                },
                {
                    test: /\.(jsx?)$/,
                    loaders: ['babel-loader'],
                    exclude: /node_modules/
                },
            ]
        },
        resolve: {
            extensions: ['.ts', '.js'],
            alias: {
                environment: path.resolve(__dirname, environmentFile),
                core: path.resolve(__dirname, coreRoot),
            }
        },
        plugins: [
            new CleanWebpackPlugin(['dist']),
            new HtmlWebPackPlugin({
                template: `./src/index.html`,
                filename: './index.html',
            }),
            new CopyWebpackPlugin([
                {from: `${coreRoot}/assets/image`, to: 'assets/core'},
                {from: `${coreRoot}/assets/audio`, to: 'assets/sounds', force: true},
                {from: `${coreRoot}/assets/particles`, to: 'assets/particles', force: true},
                {from: `${coreRoot}/languages`, to: 'assets', force: true},
            ]),
            new CopyWebpackPlugin([
                {from: `${gameRoot}/assets`, to: 'assets', force: true},
            ]),
            new VersionFile({
                output: './dist/version.txt',
                package: './package.json',
                template: './version.example.txt',
                data: {
                    environment: environment,
                    gitVersion: gitRevisionPlugin.version(),
                    gitCommitHash: gitRevisionPlugin.commithash(),
                    gitBranch: gitRevisionPlugin.branch(),
                }
            }),
            new SpritesmithPlugin({
                src: {
                    cwd: path.resolve(__dirname, 'test'),
                    glob: '*.png'
                },
                target: {
                    image: path.resolve(__dirname, './dist/assets/sprite.png'),
                    css: [
                        [path.resolve(__dirname, './dist/assets/sprite.json'), {
                            format: 'json_texture'
                        }]
                    ]
                },
                apiOptions: {
                    cssImageRef: 'sprite.png'
                }
            }),
            new ImageminPlugin({
                // test: /sprite\.(jpe?g|png|gif|svg)$/i,
                externalImages: {
                    context: 'dist',
                    sources: 'assets/sprite.png',
                    destination: 'assets/',
                    fileName: 'assets/sprite.png',
                },
                pngquant: {
                    quality: '50-60'
                },
                optipng: {
                    optimizationLevel: 9
                },
            }),
        ]
    };
};

Above was my webpack config. To answer your third question, when i said fail mean the sprite did not compress by imagemin. In this case, sprite fail to compress was the spritesheet generated by the spritesmith.

Klathmon commented 5 years ago

By "fail to compress" if you just mean the file didn't get any smaller, that might be normal.

This plugin has a failsafe where if it somehow makes the file LARGER after running it through the optimizer, it will just use the original version instead of the badly optimized version.

That happens sometimes because some tools create very highly optimized images by default, and there might not be any more optimizations that can be done to it, and trying to make any can just make it worse.

Also, the max optimizationLevel of optipng is actually 7, not 9. That could be causing issues too. Take a look at the docs for imagemin-optipng here.

I'm going to close this for now as I really think the problem is optipng not working, but if that doesn't fix it feel free to reply and I can keep trying to help!