Webpack Font Include Issue

2019-05-20 06:15发布

问题:

I have this really interesting webpack problem that I cannot figure out for the life of me.

I have the standard font-face declarations like so:

// MarkOT-ExtraLight
@font-face {
  font-family: 'MarkOT-ExtraLight';
  src: require('MarkOT-ExtraLight.eot?#iefix') format('embedded-opentype'),
       require('MarkOT-ExtraLight.otf') format('opentype'),
       require('MarkOT-ExtraLight.woff') format('woff'),
       require('MarkOT-ExtraLight.ttf')  format('truetype'),
       require('MarkOT-ExtraLight.svg#MarkOT-ExtraLight') format('svg');
  font-weight: normal;
  font-style: normal;
}

```

Now I noticed that using require worked fine except that none of my fonts were loading on my phone. So I switched from require to url and lo and behold, it all worked.

I deployed my app to heroku and it wasn't until I visited my site that I noticed that my css file had grown to 57.3 MB from 2.8 MB. Yes you heard that right, 57.3 MB. I tested it three times by switching from using require in my font-face declarations to using url to confirm that's what was actually happening.

Has anyone ever experienced something similar? I've included my webpack config below.

var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var BrowserSyncPlugin = require('browser-sync-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');

//Environment constants

const DEVELOPMENT = "development";
const PRODUCTION = "production";

// Functions for resolving all the aliases
var path_base = path.resolve(__dirname, '../');
const resolve = path.resolve;
const base = function() {
  var args = [path_base];
  args.push.apply(args, arguments);
  return resolve.apply(resolve,args);
};
const resolve_alias = base.bind(null, 'src/client');
const aliases = [
  'actions',
  'components',
  'constants',
  'containers',
  'middleware',
  'reducers',
  'routes',
  'store',
  'styles',
  'utils'
];
const resolved_aliases = aliases.reduce(function(accumulator, directory){
  accumulator[directory] = resolve_alias(directory);
  return accumulator;
}, {});

const productionVendors = [
    'react',
    'react-dom',
    'react-router',
    'redux',
    'react-redux',
    'redux-simple-router',
    'classnames',
    'underscore',
    'history',
    'immutable',
    'object-assign',
    'rx',
    'slick-carousel',
    'redux-actions'
];

const developmentVendors = [
    'react',
    'react-dom',
    'react-router',
    'redux',
    'react-redux',
    'redux-simple-router',
    'classnames',
    'underscore',
    'history',
    'immutable',
    'redbox-react',
    'object-assign',
    'rx',
    'slick-carousel',
    'redux-actions'
];

const devPlugins = [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin(),
    new HtmlWebpackPlugin({
    templateContent: function(templateParams, webpackCompiler) {
      return "<!DOCTYPE html><html><head lang='en'><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1'><title>Busy - Better marketing for all.</title></head><body><div id='app'></div><script src='vendors.js'></script><script src='main.js'></script></body></html>"
    }
  }),
  new BrowserSyncPlugin(
      {
        host: 'localhost',
        port: 7000,
        proxy: 'http://localhost:8080/webpack-dev-server/'
      },
      {
        reload: false
      }
    )
]

const productionPlugins = [
  new ExtractTextPlugin('[name].css'),
  new webpack.IgnorePlugin(/\/config$/),
  new webpack.DefinePlugin({
    'process.env': {
      NODE_ENV: JSON.stringify(PRODUCTION)
    }
  }),
  new webpack.optimize.DedupePlugin(),
  new webpack.optimize.OccurenceOrderPlugin(),
  new webpack.optimize.UglifyJsPlugin({
    compress: {
      warnings: false
    }
  })
]

const environment = process.env.NODE_ENV || DEVELOPMENT;

var config = {
  context: path.resolve(__dirname, '..'),
  entry: {
      main:
        [
          'font-awesome-webpack!./src/client/theme/font-awesome.config.js',
          path.resolve(__dirname, '..', 'src/client/index.js')
      ]
  },
  output: {
    path: path.resolve(__dirname, '..', 'dist'),
    pathInfo: true,
    filename: '[name].js'
  },
  module: {
    preLoaders: [
        {
         test: /\.js$/,
         loader: "eslint-loader",
         exclude: /node_modules/
       }
    ],
    loaders: [
      {
        test: /src\/.+.js$/,
        exclude: /node_modules/,
        loader: 'babel',
        query: {
          presets: ['react', 'es2015', 'stage-0']
        }
      },
      { test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?limit=10000&mimetype=application/font-woff" },
      { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream" },
      { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file" },
      { test: /\.otf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-sfnt" },
      { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?mimetype=image/svg+xml" },
      {
        test: /\.(jpe?g|gif|png)$/,
        loader: 'url?25000'
      },
      {
        test: /\.mp4$/,
        loader: 'file',
        exclude: /node_modules/
      }
    ]
  },
  resolve: {
    alias: resolved_aliases,
    modulesDirectories: [
       'node_modules',
       'src'
    ]
  },
  plugins: [
      new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.js')
  ]
};

// Vendor splitting
config.entry.vendors = environment === DEVELOPMENT ? developmentVendors : productionVendors

if (environment === DEVELOPMENT) {
   config.plugins = config.plugins.concat(devPlugins);
} else if (environment === PRODUCTION) {
  config.plugins = config.plugins.concat(productionPlugins);
}

// Add development server entry points
if (environment === DEVELOPMENT) {
  config.entry.main.unshift('webpack-dev-server/client?http://localhost:8080', 'webpack/hot/dev-server');
}

 // Add dev tool configurations
if (environment === DEVELOPMENT) {
  config.devServer = {
    hot: true,
    host: 'localhost',
    port: 8080,
    proxy: {"/*": "http://localhost:3000"}
  }
}

// Configure CSS and Sass loaders
if (environment === DEVELOPMENT) {
  config.module.loaders.push({ test: /.(scss|css)$/, loader: 'style!css?modules&importLoaders=3&localIdentName=[local]___[hash:base64:5]&sourceMap!autoprefixer?browsers=last 2 version!resolve-url!sass?sourceMapContents&outputStyle=expanded&sourceMap&includePaths[]=' + encodeURIComponent(require('node-bourbon').includePaths) +
'&includePaths[]=' + encodeURIComponent(require('node-neat').includePaths[1]) + '&includePaths[]=' + path.resolve(__dirname, '..', 'src/client/') });
 } else if (environment === PRODUCTION) {
   config.module.loaders.push({ test: /.(scss|css)$/, loader: ExtractTextPlugin.extract('style','css?modules&importLoaders=3&localIdentName=[local]___[hash:base64:5]&sourceMap!autoprefixer?browsers=last 2 version!resolve-url!sass?sourceMap&includePaths[]=' + encodeURIComponent(require('node-bourbon').includePaths) +
'&includePaths[]=' + encodeURIComponent(require('node-neat').includePaths[1]) + '&includePaths[]=' + path.resolve(__dirname, '..', 'src/client/') ) });

}

 // Configure devtool
if (environment === DEVELOPMENT) {
  config.devtool = 'inline-source-map';
} else if (environment === PRODUCTION) {
  config.devtool = 'source-map';
}

module.exports = config;

回答1:

Try to reduce the limit to 100 for example, that will prevent webpack to include the fonts inside the file.

{
   test: /\.(woff2|woff|ttf|eot|svg|otf)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
   loaders: ["url-loader?limit=100&name=fonts/[name]_[hash].[ext]"]
}

The loader above will copy your fonts file to your a fonts folder inside the your destination folder.