I'm using the following WordPress starter plugin with a full working Vue configuration implemented: https://github.com/tareq1988/vue-wp-starter
This plugin works in general. But seems that there is a Webpack issue which is responsible to generate some css files.
This is the Webpack configuration:
const webpack = require("webpack");
const path = require("path");
const package = require("./package.json");
const { VueLoaderPlugin } = require("vue-loader");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const BrowserSyncPlugin = require("browser-sync-webpack-plugin");
const TerserJSPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const config = require("./config.json");
const devMode = process.env.NODE_ENV !== "production";
// Naming and path settings
var appName = "app";
var entryPoint = {
frontend: "./src/frontend/main.js",
admin: "./src/admin/main.js",
style: ['./assets/less/style.less', './assets/scss/style.scss'],
};
var exportPath = path.resolve(__dirname, "./assets/js");
// Enviroment flag
var plugins = [];
// extract css into its own file
plugins.push(
new MiniCssExtractPlugin({
filename: "../css/[name].css",
ignoreOrder: true
})
);
plugins.push(
new webpack.DefinePlugin({
__VUE_OPTIONS_API__: false,
__VUE_PROD_DEVTOOLS__: false,
}),
)
// enable live reload with browser-sync
// set your WordPress site URL in config.json
// file and uncomment the snippet below.
// --------------------------------------
// plugins.push(new BrowserSyncPlugin( {
// proxy: {
// target: config.proxyURL
// },
// files: [
// '**/*.php'
// ],
// cors: true,
// reloadDelay: 0
// } ));
plugins.push(new VueLoaderPlugin());
// Differ settings based on production flag
if (devMode) {
appName = "[name].js";
} else {
appName = "[name].min.js";
}
module.exports = {
entry: entryPoint,
mode: devMode ? "development" : "production",
output: {
path: exportPath,
filename: appName,
},
resolve: {
alias: {
vue$: "vue/dist/vue.esm-bundler.js",
"#": path.resolve("./src/"),
frontend: path.resolve("./src/frontend/"),
admin: path.resolve("./src/admin/"),
},
modules: [
path.resolve("./node_modules"),
path.resolve(path.join(__dirname, "src/")),
],
},
optimization: {
runtimeChunk: "single",
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\\/]node_modules[\\\/]/,
name: "vendors",
chunks: "all",
},
},
},
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
},
plugins,
module: {
rules: [
{
test: /\.vue$/,
loader: "vue-loader",
},
{
test: /\.js$/,
use: "babel-loader",
exclude: /node_modules/,
},
{
test: /\.less$/,
use: ['vue-style-loader', "css-loader", "less-loader"],
},
{
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader'
]
},
{
test: /\.png$/,
use: [
{
loader: "url-loader",
options: {
mimetype: "image/png",
},
},
],
},
{
test: /\.svg$/,
use: "file-loader",
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: (resourcePath, context) => {
return path.relative(path.dirname(resourcePath), context) + "/";
},
hmr: process.env.NODE_ENV === "development",
},
},
"css-loader",
],
},
],
},
};
This is the folder structure for the relevant part:
Starting the app with npm run dev I get no error messages. But I expect the files /assets/css/admin.css and /assets/css/frontend.css to automatically be created. This is what the developer says here:
Also the paths are included in the related PHP files for WordPress (includes/Assets.php):
So I get the following 404 error:
....plugin-root/assets/css/admin.css?ver=0.1.0 net::ERR_ABORTED 404 (Not Found)
Long description in short: The configurator for this starter plugin should generate two css files which are missing. What could be the reason for this? Do I miss something?
Related
Simple webpack setup, when I use import to load my scss it is completely missing from the bundle. The line where the import should be is simply missing. When I use require instead, it works.
optimization: {usedExports: true} is not the problem, I tried with and without
mini-css-extract-plugin also did not work.
when I put a typo in the scss it complains, so it is parsed but simply not bundled in the end?
index.js
require("./scss/style.scss");
//import "./scss/style.scss" <--- not working
import { createApp } from 'vue';
import App from './components/App.vue';
const el = document.getElementById('app');
createApp(App).mount(el);
webpack config
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader');
const { DefinePlugin } = require('webpack');
const dist = path.resolve(__dirname, "dist");
module.exports = env => {
const mode = env.production == true ? "production" : "development";
const devtool = mode == "production" ? false : "inline-source-map";
return {
mode: mode,
entry: './web/index.js',
output: {
filename: 'bundle.js',
path: dist
},
optimization: {
usedExports: true,
},
devServer: {
static: {
directory: dist
},
port: 8888
},
module: {
rules: [{
test: /\.(sa|sc|c)ss$/,
use: [
'style-loader',
'css-loader',
'sass-loader',
],
}, {
test: /\.(ttf|eot|woff|woff2|svg)$/,
use: {
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
},
},
}, {
test: /\.vue$/,
loader: 'vue-loader'
}]
},
plugins: [
new CleanWebpackPlugin(),
new DefinePlugin({
__VUE_OPTIONS_API__: false,
__VUE_PROD_DEVTOOLS__: false,
}),
new HtmlWebpackPlugin({
template: path.resolve("./web/index.html")
}),
new VueLoaderPlugin()
],
resolve: {
extensions: ['.js'],
alias: {
"#": path.resolve(__dirname, 'web')
}
},
devtool
};
};
I found the problem but I don't understand why webpack drops it.
Quote from https://webpack.js.org/guides/tree-shaking/
Note that any imported file is subject to tree shaking. This means if you use something like css-loader in your project and import a CSS file, it needs to be added to the side effect list so it will not be unintentionally dropped in production mode:
In my package.json I put
"sideEffects": false,
to be able to use treeshaking.
But I had to disable it in the loader rule
{
test: /\.(sa|sc|c)ss$/,
use: ['style-loader','css-loader','sass-loader'],
sideEffects: true <----
}
I'm putting together a project with webpack 4. Virtually all of it working as it should, I'm just having trouble with minifying CSS.
If in my entrypoint i include a.css or .less file then everything works correctly. It also works correctly if i use #include './myfile.less'. However if I use #include './myfile.css' that section is imported without being minified.
How do I get imported CSS files to work?
webpack.config
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: {
'app': './src/app/app.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js'
},
module: {
rules: [
{
test: /\.html/,
use: 'html-loader'
},
{
test: /\.less$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
"css-loader",
"less-loader"
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader?name=assets/images/[path][name].[ext]?[hash]']
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader?name=assets/fonts/[name].[ext]?[hash]'
]
}
],
},
plugins: [
new HtmlWebpackPlugin({ template: './src/public/index.html' }),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: "[name].bundle.css",
chunkFilename: "[id].css"
}),
]
};
While webpack 5 is likely to come with a CSS minimizer built-in, with webpack 4 you need to bring your own. To minify the output, use a plugin like optimize-css-assets-webpack-plugin. Setting optimization.minimizer overrides the defaults provided by webpack, so make sure to also specify a JS minimizer
webpack.config.js
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
module.exports = {
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true // set to true if you want JS source maps
}),
new OptimizeCSSAssetsPlugin({})
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
],
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader"
]
}
]
}
}
Reference
I found notes on MiniCssExtractPlugin production usage.
Following these fixed the issue:
specifically adding:
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
...
module.exports = {
...
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true // set to true if you want JS source maps
}),
new OptimizeCSSAssetsPlugin({})
]
},
}
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
minimize: true
}
}
]
I'm set postcss-loader + style-loader on webpack, and I'am using webpack-dev-server, but every time that change css, the webpack don't rebuild.
script webpack dev server I use on scripts npm:
webpack-dev-server --hot
webpack.config.js
const path = require('path')
const webpack = require('webpack')
const lost = require('lost')
const mqpacker = require('css-mqpacker')
const precss = require('precss')
const cssnano = require('cssnano')
const nested = require('postcss-nested')
const cssnext = require('postcss-cssnext')
const atImport = require('postcss-import')
const postCSSFocus = require('postcss-focus')
const pxtorem = require('postcss-pxtorem')
const flexBugsFixes = require('postcss-flexbugs-fixes')
const rucksack = require('rucksack-css')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const objectFit = require('postcss-object-fit-images')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const StatsPlugin = require('stats-webpack-plugin')
const environment = process.env.NODE_ENV
module.exports = {
devServer: {
colors: true,
historyApiFallback: true,
inline: false,
port: 8080,
},
entry: [
'webpack/hot/dev-server?reload=true',
path.join(__dirname, 'src/script/app.js')
],
output: {
path: path.join(__dirname, '/build/'),
filename: 'index.js',
publicPath: '/'
},
resolve: {
extensions: ['', '.js', '.css', '.json']
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html',
inject: 'body',
filename: 'index.html'
}),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new ExtractTextPlugin('[name].min.css'),
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false,
screw_ie8: true
}
}),
new StatsPlugin('webpack.stats.json', {
source: false,
modules: false
}),
new CopyWebpackPlugin([{
context: 'src/svg',
from: '*.svg',
to: 'svg'
}])
],
module: {
loaders: [{
test: /\.worker\.js$/,
loader: 'babel!worker?inline!'
}, {
test: /\.js?$/,
exclude: [/node_modules/, /\.worker\.js$/],
loader: 'babel'
}, {
test: /\.mod\.css$/,
loader: ExtractTextPlugin.extract('style', 'css?modules!postcss')
}, {
test: /\.css$/,
exclude: /\.mod\.css$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader!postcss-loader')
}, {
test: /\.(png|jpe?g|svg|gif)$/,
loaders: [
'file?hash=sha512&digest=hex&name=[hash].[ext]',
'image-webpack?{progressive:true, optimizationLevel: 7, interlaced: false, pngquant:{quality: "65-90", speed: 4}}'
]
}, {
test: /\.svg$/,
loader: 'url?limit=65000&mimetype=image/svg+xml&name=fonts/[name].[ext]'
}, {
test: /\.woff$/,
loader: 'url?limit=65000&mimetype=application/font-woff&name=fonts/[name].[ext]'
}, {
test: /\.woff2$/,
loader: 'url?limit=65000&mimetype=application/font-woff2&name=fonts/[name].[ext]'
}, {
test: /\.[ot]tf$/,
loader: 'url?limit=65000&mimetype=application/octet-stream&name=fonts/[name].[ext]'
}, {
test: /\.eot$/,
loader: 'url?limit=65000&mimetype=application/vnd.ms-fontobject&name=fonts/[name].[ext]'
}],
resolve: {
extensions: ['', '.js', '.css', '.json']
}
},
postcss: compiler => [
atImport({
addDependencyTo: compiler
}),
precss,
cssnext({
browsers: ['last 2 versions']
}),
pxtorem({
propWhiteList: ['font', 'font-size', 'line-height', 'letter-spacing'],
selectorBlackList: []
}),
lost,
postCSSFocus,
flexBugsFixes,
rucksack,
objectFit,
nested,
mqpacker,
cssnano({
autoprefixer: false
})
]
}
Lack configure something? Because in Webpack documentation, can not find anything about
Did you require the css file in your main javascript file? For example, in your index.jsx:
require("somestyle.css");
css-loader will only know about the CSS files that the application has required. For more information, see: https://github.com/webpack/css-loader
I am trying to use extract-text-webpack-plugin to generate an app.css in my output folder (in my entry js I am importing scss's ).
I saw this:
Webpack "OTS parsing error" loading fonts
It actually helped because if I use the full path as my publicPath then it works but that means that for some reason extract-text-webpack-plugin doesn't.
my config:
'use strict';
var webpack = require('webpack');
var autoprefixer = require('autoprefixer');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var ngAnnotatePlugin = require('ng-annotate-webpack-plugin');
module.exports = function makeWebpackConfig (options) {
var BUILD = !!options.BUILD;
var config = {};
config.entry = {
app: './app.js',
iosCordova: ['./static/wrapper/js/ios/cordova_all.min.js'],
androidCordova: ['./static/wrapper/js/android/cordova_all.min.js']
};
config.output = {
path: __dirname + '/_dist',
//the commented out works without generating an app.css in output
//publicPath: BUILD ? 'http://danny.il.corner.com:2222/' : 'http://danny.il.corner.com:8080/',
publicPath: BUILD ? '/' : 'http://danny.il.corner.com:8080/',
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js'
};
if (BUILD) {
config.devtool = 'source-map';
} else {
config.devtool = 'eval';
}
config.module = {
noParse: /node_modules\/html2canvas/,
preLoaders: [],
loaders: [
{
test: /\.js$/,
loader: 'babel',
query: {
presets: ['es2015'],
plugins: ['transform-runtime'],
comments: true,
compact: false
},
exclude: [
/node_modules/,
/cordova_all/
]
},
{
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/,
loader: 'file?name=[name].[ext]'
}, {
test: /\.html$/,
loader: "ngtemplate?relativeTo=" + __dirname + "!raw"
}
,
{
test: /\.(css)$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader!postcss-loader')
},
{
test: /\.less$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")
},
{
test: /\.scss$/,
loaders: ["style", "css?sourceMap", "sass?sourceMap"]
}
]
};
config.postcss = [
autoprefixer({
browsers: ['last 3 versions']
})
];
config.plugins = [
new ExtractTextPlugin('[name].css'),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
,
new ngAnnotatePlugin({
add: true
})
];
config.plugins.push(
new HtmlWebpackPlugin({
template: './index.html',
inject: true,
excludeChunks: ['app','iosCordova','androidCordova']
})
);
if (BUILD) {
config.plugins.push(
new webpack.NoErrorsPlugin(),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin()
)
}
config.devServer = {
stats: {
modules: false,
cached: false,
colors: true,
chunk: false
}
};
return config;
};
thanks for the helpers :)
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;
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.