jeerbl/webfonts-loader

Minification not working?

enrique-ramirez opened this issue · 7 comments

I'm not sure what's going on, but minification is not working. I have a bunch of CSS that all gets minified. After checking the compiled styles.css file, I can see my minified CSS and after it I can see the generated font CSS un-minified. I'm using webpack's mode: "production" only to achieve this. Not sure if I'm doing something wrong.

webpack.common.js
const webpack = require('webpack')
const path = require('path')
const CircularDependencyPlugin = require('circular-dependency-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CopyPlugin = require('copy-webpack-plugin')

module.exports = (options) => ({
  mode: options.mode,
  watch: options.watch || false,
  devtool: options.devtool,
  entry: {
    app: path.join(process.cwd(), 'src/app.js'),
  },
  // eslint-disable-next-line prefer-object-spread
  output: Object.assign({
    filename: 'assets/js/[name].js',
    chunkFilename: 'assets/js/[name].chunk.js',
    path: path.resolve(process.cwd(), 'dist'),
    publicPath: './',
  }, options.output),
  externals: {
    jquery: 'jQuery',
  },
  module: {
    rules: [
      {
        test: /\.(gif|png|jpe?g|svg)$/i,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '[name].[ext]',
              outputPath: 'assets/img',
            },
          },
          {
            loader: 'image-webpack-loader',
            options: {
              disable: options.mode === 'development',
            },
          },
        ],
      },
      {
        test: /(\.jsx|\.js)$/,
        use: ['babel-loader?cacheDirectory=true', 'eslint-loader'],
        exclude: /(node_modules)/,
      },
      {
        test: /\.font\.js/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              url: false,
            },
          },
          {
            loader: 'webfonts-loader',
            options: {
              publicPath: './',
            },
          },
        ],
      },
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              modules: {
                localIdentName: '[local]',
              },
              sourceMap: true,
            },
          },
          'postcss-loader',
        ],
      },
    ],
  },
  optimization: {
    splitChunks: {
      name: 'vendor',
    },
  },
  plugins: options.plugins.concat([
    new webpack.NoEmitOnErrorsPlugin(),
    new webpack.optimize.ModuleConcatenationPlugin(),
    new CircularDependencyPlugin({
      exclude: /a\.js|node_modules/,
      failOnError: false,
    }),
    new MiniCssExtractPlugin({
      filename: 'style.css',
    }),
    new CopyPlugin([
      { from: 'src/screenshot.png', to: 'screenshot.png' },
      { from: 'src/favicon.png', to: 'favicon.png' },
      {
        from: 'src/**/*.php',
        to: './',
        transformPath(targetPath) {
          return targetPath.replace('src/', '')
        },
      },
    ]),
  ]),
  resolve: {
    modules: [path.resolve(__dirname, '../..', 'src'), 'node_modules'],
    extensions: [
      '.js',
    ],
    mainFields: [
      'browser',
      'jsnext:main',
      'main',
    ],
  },
  target: 'web',
  performance: options.performance || {},
})
webpack.prod.js
module.exports = require('./webpack.common')({
  mode: 'production',
  devtool: 'source-map',
  plugins,
  performance: {
    assetFilter: (assetFilename) => !(/(\.map$)|(^(main\.|favicon\.))/.test(assetFilename)),
  },
})
icons.font.js
module.exports = {
  files: ['./*.svg'],
  fontName: 'ttc',
  classPrefix: 'icon--',
  baseSelector: '.icon',
  types: ['eot', 'woff', 'woff2', 'ttf', 'svg'],
  fileName: 'assets/fonts/[fontname].[chunkhash].[ext]',
  cssTemplate: './css.hbs',
}
css.hbs
@font-face {
  font-family: "{{fontName}}";
  src: {{{src}}};
}

{{baseSelector}} {
  line-height: 1;
}

{{baseSelector}}:before {
  font-family: {{fontName}} !important;
  font-style: normal;
  font-weight: normal !important;
  vertical-align: middle;
}

{{#each codepoints}}
.{{../classPrefix}}{{@key}}:before {
  content: "\\{{this}}";
}
{{/each}}
app.js
import 'css/style.css'
import 'icons/icons.font'

// ...rest of app

I think that you should add OptimizeCSSAssetsPlugin for proper minification.

@DamianOsipiuk So webpack's built-in tools won't work. Do you happen to know the reason? I'd like to avoid extra plugins since mode: "production" works wonders for me except on this one case.

If you have an idea on where the issue may be, I'll gladly dive into the code and try and fix the issue.

@enrique-ramirez I have two ideas:

  1. Add postcss-loader after webfonts-loader but before css-loader. This should work since I think postcss is minifig stylesheets in your setup.
  2. Add OptimizeCSSAssetsPlugin. It's using css-nano for minification which I believe is also used in postcss. https://github.com/NMFR/optimize-css-assets-webpack-plugin

@DamianOsipiuk thank you, you were right. Adding 'postcss-loader' before webfonts-loader but after css-loader (so the other way round than what you mentioned) did work. Here's how it looks in the end:

{
  test: /\.font\.js/,
  use: [
    MiniCssExtractPlugin.loader,
    {
      loader: 'css-loader',
      options: {
        url: false,
      },
    },
    'postcss-loader',
    {
      loader: 'webfonts-loader',
      options: {
        publicPath: './',
      },
    },
  ],
},

Feel free to close this issue!

@enrique-ramirez Actually webpack loaders are evaluated from right to left (bottom to top), so i have applied mental shortcut. Sorry about that :D

@DamianOsipiuk I didn't know that. Thanks for sharing!

Stale issue message