I'm deploying my first webpack app. I probably have a few misconceptions.
My (simple) app is Webpack2 + Bootstrap4 + ReactJS.
I ran ... npm run prod (the optimizing sequence).
My "dist" folder now contains the files & folder that I list below.
I use DigitalOcean, Nginx, express, ... to deploy my Webpack app.
I uploaded my Webpack app into a directory that is in my DigitalOcean top directory.
In this directory named "wp2-bs4-rjs", I placed:
index.html, app.bundle.js, app.css, imgs (folder).
This "wp2-bs4-rjs" directory also contains:
package.json (for express) & node_modules folder (for express, for deployment).
I'm assuming my Webpack app does not use the node_modules folder,
now that it has been optimized (?).
IMPORTANT: When I use webpack-dev-server in my computer's localhost,
the Bootstrap & jQuery works (everything works).
BUT, when I view my Webpack app online, I see the text and its background image,
but no Bootstrap influence.
Since I see my background image & my css styles, I know the app.css file is properly working.
Also, since I see my text, I know my app.bundle.js file is partially working.
BUT, for some reason, the Bootstrap & jQuery in my app.bundle.js file is not working.
I have no errors in my JavaScript console & the networking tab.
Do you have any ideas of what I'm doing wrong ?
Here's it's URL: wp2-bs4-rjs
My Webpack app is served on my domain's localhost, port 3000, using reverse proxy.
- - - - - - - - - - - - - - - - - -
Thank-you, MLR
========================================================================
Update: I tried installing a few Node packages as dependencies,
to see if it made a difference. It did not.
Installed in my DigitalOcean server & my computer's webpack-dev-server (Webpack project):
"babel-cli": "^6.24.1", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", "bootstrap": "^4.0.0-alpha.6", "express": "^4.15.3", "jquery": "^3.2.1", "react": "^15.6.1", "react-dom": "^15.6.1", "tether": "^1.4.0", "webpack": "^3.0.0"
- - - - - - - - - - - - - - - - - -
Not installed in my DigitalOcean server >Webpack project,
but is installed in my computer's webpack-dev-server version:
ejs, css-loader, style-loader, sass-loader, node-sass, extract-text-webpack-plugin, webpack-dev-server, babel-loader, babel-core, rimraf, file-loader, image-webpack-loader, libpng, bootstrap-loader, resolve-url-loader, url-loader, imports-loader exports-loader, postcss postcss-loader, purifycss-webpack, purify-css
========================================================================
Update: Since the node_modules folder is in the same directory as app.bundle.js ...
& all the other (non-image) files, ...
in the app.bundle.js, I tried changing all occurrences of ./node_modules to node_modules.
It did not work. Although my problem could be a combination of errors.
========================================================================
Hi olore, here's my Webpack config (as you asked).
'use strict';
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const glob = require('glob');
const PurifyCSSPlugin = require('purifycss-webpack');
const isProd = process.env.NODE_ENV === 'production';
const cssDev = ['style-loader','css-loader', 'resolve-url-loader', 'sass-loader'];
const cssProd = ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader','sass-loader'],
publicPath: '/dist'
});
let cssConfig = isProd ? cssProd : cssDev;
module.exports = {
entry: {
app: './src/app.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js'
},
resolve: { extensions: ['.js','.jsx','.html','.css','.scss'] },
module: {
rules: [{
test: /\.scss$/,
use: cssConfig// potentially the ExtractTextPlugin.extract(...)
},{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
},{
test: /\.(jpe?g|png|gif|svg)$/i,
use: [
'file-loader?name=[name].[ext]&outputPath=imgs/&publicPath=./',
'image-webpack-loader'
]
},{
test: /\.(woff2?|svg)$/,
use: 'url-loader?limit=10000&name=fonts/[name].[ext]'
},{
test: /\.(ttf|eot)$/,
use: 'file-loader&name=fonts/[name].[ext]'
},{
test: /bootstrap[\/\\]dist[\/\\]js[\/\\]umd[\/\\]/,
use: 'imports-loader?jQuery=jquery'
}
],
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
hot: true,
open: true,
stats: 'errors-only'
},
plugins: [
new HtmlWebpackPlugin({
title: 'ReactJS Webpack Bootstrap',
hash: true,
template: './index.html',
minify: {collapseWhitespace: true}
}),
new ExtractTextPlugin({
filename: '[name].css',
disable: !isProd,
allChunks: true
}),
new PurifyCSSPlugin({
paths: glob.sync(path.join(__dirname, 'index.html')),
purifyOptions: { minify: true }
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery",
Tether: "tether",
"window.Tether": "tether",
Alert: "exports-loader?Alert!bootstrap/js/dist/alert",
Button: "exports-loader?Button!bootstrap/js/dist/button",
Carousel: "exports-loader?Carousel!bootstrap/js/dist/carousel",
Collapse: "exports-loader?Collapse!bootstrap/js/dist/collapse",
Dropdown: "exports-loader?Dropdown!bootstrap/js/dist/dropdown",
Modal: "exports-loader?Modal!bootstrap/js/dist/modal",
Popover: "exports-loader?Popover!bootstrap/js/dist/popover",
Scrollspy: "exports-loader?Scrollspy!bootstrap/js/dist/scrollspy",
Tab: "exports-loader?Tab!bootstrap/js/dist/tab",
Tooltip: "exports-loader?Tooltip!bootstrap/js/dist/tooltip",
Util: "exports-loader?Util!bootstrap/js/dist/util"
})
]
};
Related
I developed a debug extension which uses an external js debugger adapter. I put the js file to the bin directory looks like this.
rootDir
--bin
----adapter.js
And I used it like this in my development environment.
{
"label": "ThingIO Debugger",
"program": "./bin/adapter.js",
"runtime": "node",
"type": "thingio-debug"
}
The code works well in my development mode, but when I packaged it to a .vsix file and install to another machine, it failed immediately.
The webpack file is below
//#ts-check
'use strict';
const path = require('path');
//#ts-check
/** #typedef {import('webpack').Configuration} WebpackConfig **/
/** #type WebpackConfig */
const extensionConfig = {
target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
output: {
// the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
path: path.resolve(__dirname, 'dist'),
filename: 'extension.js',
libraryTarget: 'commonjs2'
},
externals: {
vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
// modules added here also need to be added in the .vscodeignore file
},
resolve: {
// support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
extensions: ['.ts', '.js']
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: [
{
loader: 'ts-loader'
}
]
}
]
},
devtool: 'nosources-source-map',
infrastructureLogging: {
level: "log", // enables logging required for problem matchers
},
};
module.exports = [ extensionConfig ];
And the vscode:prepublish command is webpack --mode production --devtool hidden-source-map
I think it looks like the debugger adapter program is not found. So I checked the ~/.vscode/extensions, and the adapter js file exists in the right path.
Now I'm very confused about what wrong is with the extension. Maybe the path is wrong or the webpack did not compile the right file in some situation?
Can anyone give some solution or suggestion about this?
I am trying to set up a PWA for an app in Laravel (5.8) with vuejs (2.5).
This is the configuration I have in mix.js:
...
mix.js('resources/js/app.js', 'public/js')
.generateSW({
// Define runtime caching rules.
runtimeCaching: [{
// Match any request that ends with .png, .jpg, .jpeg or .svg.
urlPattern: /\.(?:png|jpg|jpeg|svg)$/,
// Apply a cache-first strategy.
handler: 'CacheFirst',
options: {
// Use a custom cache name.
cacheName: 'images',
// Only cache 10 images.
expiration: {
maxEntries: 10,
},
},
}],
skipWaiting: true
})
.vue()
.copy('node_modules/lodash/lodash.min.js', 'public/js')
.copy('./resources/manifest.json', 'public/dist/manifest.json')
.copy('./resources/icons', 'public/dist/')
.extract(['vue'])
.webpackConfig({
output: {
filename: '[name].js',
chunkFilename: `[name].chunk.[contenthash:8].js`,
path: path.join(__dirname, 'public/dist'),
publicPath: '/dist/'
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.common.js',
'variables': path.resolve('resources/sass/_variables.scss')
}
},
plugins: [
new webpack.ContextReplacementPlugin(
/moment[\/\\]locale$/,
/(en|es)$/
),
]
})
.options({
processCssUrls: false,
});
...
The service worker was installed correctly and the first time it loads it caches my assets.
But the next calls I make (reload the page) don't use that cache and reload the assets from the network.
However, what I am looking for is a quick initial load after the PWA is installed and this is not happening.
I have done this before with Angular and the PWA module and the assets are loaded from cache, and if there are changes, they are updated later, which makes the initial load of the application very fast.
Can someone help me with this?
In the end I ended up using workbox-cli with this setup:
// workbox.config.js
module.exports = {
"globDirectory": "public/",
"globPatterns": [
"**/*.{js,css,ico,woff2,webmanifest}",
"**/images/icons/*",
"**/images/*",
],
// 15mb max file size
maximumFileSizeToCacheInBytes: 15 * 1024 * 1024,
globIgnores: [
'**/mix-manifest.json',
'**/js/{manifest,vendor}.js',
'**/js/chunks/*',
],
"swDest": "public/service-worker.js",
"swSrc": "resources/sw-offline.js"
};
And running this at the end of my npm run prod
workbox injectManifest workbox.config.js
All credit to this repository:
https://github.com/aleksandertabor/flashcards
I want to embed a react-native-web application into an existing website and am currently looking for options how to do so.
The application should be a quite simple questionnaire which needs to be embedded into a website created with Elementor. My idea was to use the Elementor HTML widget and insert my application somehow, but unfortunately I cannot figure out how to do this.
I've got a bit of experience developing React Native(RN) apps but I am pretty new to web development and therefore thought it would be easier for me to go with RN and the react-native-web library.
So far, I've created a RN project using npx react-native init WebApp, copied the App.js, index.js and package.json files from react-native-web CodeSandbox template, deleted the node_modules folders and ran npm install. Then I was able to start and build this example web app with the scripts from the package.json.
Now my question, how can I use the output from the build directory and embed it into an html tag?
I also tried to use webpack with the configuration from the react-native-web docs to bundle the app but I always got a new error as soon as I fixed the last one. Is it possible to bundle a RN app into a single JS file which I could then insert into the website?
Looking forward to any advice!
Marco
I solved it by using the below webpack config. The created bundle.web.js' content is put into a script tag (<script>...</script>). This can be embedded into the HTML widget.
// web/webpack.config.js
const path = require('path');
const webpack = require('webpack');
const appDirectory = path.resolve(__dirname, '');
// This is needed for webpack to compile JavaScript.
// Many OSS React Native packages are not compiled to ES5 before being
// published. If you depend on uncompiled packages they may cause webpack build
// errors. To fix this webpack can be configured to compile to the necessary
// `node_module`.
const babelLoaderConfiguration = {
test: /\.js$/,
// Add every directory that needs to be compiled by Babel during the build.
include: [
path.resolve(appDirectory, 'index.web.js'),
path.resolve(appDirectory, 'src'),
path.resolve(appDirectory, 'node_modules/react-native-uncompiled'),
],
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
// The 'metro-react-native-babel-preset' preset is recommended to match React Native's packager
presets: ['module:metro-react-native-babel-preset'],
// Re-write paths to import only the modules needed by the app
plugins: ['react-native-web'],
},
},
};
// This is needed for webpack to import static images in JavaScript files.
const imageLoaderConfiguration = {
test: /\.(gif|jpe?g|png|svg)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
},
},
};
module.exports = {
entry: [
// load any web API polyfills
// path.resolve(appDirectory, 'polyfills-web.js'),
// your web-specific entry file
path.resolve(appDirectory, 'src/index.js'),
],
// configures where the build ends up
output: {
filename: 'bundle.web.js',
path: path.resolve(appDirectory, 'dist'),
},
// ...the rest of your config
module: {
rules: [babelLoaderConfiguration, imageLoaderConfiguration],
},
resolve: {
// This will only alias the exact import "react-native"
alias: {
'react-native$': 'react-native-web',
},
// If you're working on a multi-platform React Native app, web-specific
// module implementations should be written in files using the extension
// `.web.js`.
extensions: ['.web.js', '.js'],
},
};
Edit [23-7-2019]
After further research, I found that not ALL .vue files have this problem. Some do still show the original source code.
It looks like one of the loaders that is used, might be the culprit for the problems (with "vue-loader" as my first 'target').
In files that DO show the source code, the relevant part of the source map file looks like this:
Whereas the same part of the source map in the files without the source code, looks like this:
So for some reason, the "harmony default export" of the vue-loader seems to be missing for the latter type of files.
Previous issue text
Since a few days, the source maps for my .vue files no longer contain the original code (sourcesContent).
A number of source map files are generated by Webpack, but none of them contain the actual code: only minified or otherwise 'compressed' versions of the code, which are not very usable. They look like this:
The Typescript (.ts) files in my project, look almost correct, but still contain some minor forms of modification, e.g.:
What I have tried:
- I have searched Stackoverflow, and found a number of similar questions (e.g. like WebPack sourcemaps confusing (duplicated files)) with possible fixes, but none of them fixed my problem;
- I have compared my latest (Webpack) changes with that of about a week (and 2 weeks) ago, when all was working okay. And I have compared it also to a very
similar project that still produces correct source maps, including
for .vue files.
- I have tried various settings for the "devtool" setting in the Webpack config, but nothing helped.
- I am not using Uglify (which is mentioned a lot when people have a problem with source maps), so that cannot be the problem;
- I have tried updating a number of build related packages, so that they are equal to those of the project which is still working correctly, but the problem remains.
- I checked different browsers, but the problem occurs both in Chrome and Firefox (and I checked that their source map settings are set to 'on', which they have to be as the other project is working with the same settings). I even tried IE11, but that didn't help either.
My starting scripts in package.json look like this:
"build-watch": "webpack -d --watch true --config webpack.dev.config.js",
"build-release": "webpack -p --config webpack.production.config.js",
"build-dev": "webpack -d --config webpack.dev.config.js",
The devDependencies look like this:
"devDependencies": {
"#babel/core": "^7.5.5",
"#babel/plugin-proposal-class-properties": "^7.5.5",
"#babel/plugin-proposal-object-rest-spread": "^7.5.5",
"#babel/preset-env": "^7.5.5",
"#babel/preset-typescript": "^7.3.3",
"#types/bootstrap": "^4.3.1",
"#types/jest": "^24.0.15",
"#types/jquery": "^3.3.30",
"#types/webpack": "^4.4.35",
"#vue/cli-plugin-e2e-cypress": "^3.9.0",
"#vue/cli-plugin-eslint": "^3.9.2",
"#vue/cli-plugin-typescript": "^3.9.0",
"#vue/cli-plugin-unit-jest": "^3.9.0",
"#vue/cli-service": "^3.9.3",
"#vue/eslint-config-standard": "^4.0.0",
"#vue/eslint-config-typescript": "^4.0.0",
"#vue/test-utils": "1.0.0-beta.29",
"assets-webpack-plugin": "^3.9.10",
"babel-loader": "^8.0.6",
"babel-preset-vue": "^2.0.2",
"cache-loader": "^4.1.0",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.1.0",
"cssnano": "^4.1.10",
"cypress": "^3.4.0",
"es6-promise": "^4.2.8",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.2.3",
"globule": "^1.2.1",
"mini-css-extract-plugin": "^0.7.0",
"node-sass": "^4.12.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-increase-specificity": "^0.6.0",
"postcss-loader": "^3.0.0",
"style-loader": "^0.23.1",
"ts-jest": "^24.0.2",
"ts-loader": "^6.0.4",
"typescript": "^3.5.3",
"url-loader": "^2.0.1",
"vue-loader": "^15.7.1",
"vue-template-compiler": "^2.6.10",
"webpack": "^4.36.1",
"webpack-bundle-analyzer": "^3.3.2",
"webpack-cli": "^3.3.6" },
And the most relevant parts of my Webpack development config (excluding stuff like those related to webfonts) are these:
const path = require('path');
const webpack = require('webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const AssetsPlugin = require('assets-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const bundleOutputDir = './wwwroot/dist';
const NODE_PATH = path.join(__dirname, "node_modules");
const CACHE_PATH = path.join(NODE_PATH, '.cache/vue');
const VUE_VERSION = require('vue/package.json').version;
const VUE_LOADER_VERSION = require('vue-loader/package.json').version;
const bundleConfig = require('./bundles.config.js');
const buildId = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
const config = {
entry: bundleConfig.entries,
output: {
path: path.join(__dirname, bundleOutputDir),
filename: '[name].js',
publicPath: 'dist/'
},
mode: 'development',
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader'
},
{
test: /\.css$/,
exclude: [
path.resolve(__dirname, "wwwroot", "Content"),
path.resolve(__dirname, "src", "common")
],
use: [
'vue-style-loader',
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
},
{
test: /\.css$/,
include: [
path.resolve(__dirname, "wwwroot", "Content"),
path.resolve(__dirname, "src", "common")
],
use: [
'vue-style-loader',
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
cacheDirectory: CACHE_PATH,
cacheIdentifier: [
'development',
webpack.version,
VUE_VERSION,
VUE_LOADER_VERSION
].join('|')
}
},
{
test: /\.tsx$/,
loaders: 'babel-loader',
include: /src/
},
{
test: /\.ts$/,
loaders: 'ts-loader',
include: /src/,
options: {
appendTsSuffixTo: [
/\.vue$/
]
}
}, ...
]
},
devtool: "cheap-module-eval-source-map",
resolve: {
extensions: [
'.js',
'.vue',
'.tsx',
'.ts'
],
alias: {
'~#': path.resolve('src'),
'vue$': 'vue/dist/vue.esm.js',
'bootstrap-vue$': 'bootstrap-vue/dist/bootstrap-vue.esm.js'
}
},
plugins: [
new VueLoaderPlugin(),
new webpack.ProvidePlugin({
'Promise': 'es6-promise'
}),
new CleanWebpackPlugin(),
new webpack.optimize.ModuleConcatenationPlugin(),
new MiniCssExtractPlugin({ filename: "[name].css" }),
new OptimizeCssAssetsPlugin({
cssProcessor: require('cssnano'),
cssProcessorPluginOptions: {
preset: ['default', { discardComments: { removeAll: false } }],
}
}),
new webpack.WatchIgnorePlugin([
/\.d\.ts$/
]),
new AssetsPlugin({
filename: 'webpack.assets.json',
path: bundleOutputDir,
prettyPrint: true,
metadata: { buildId: buildId }
})
],
stats: {
modules: false,
entrypoints: false,
children: false
},
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
chunks: "all"
}
}
}
} };
I have totally run out of clues, so if anyone can give some, that would be great!
In the end, it turned out to be a source maps caching issue...! Which seems like a "duh!" solution to the problem, but it is not, really.
Because, it turns out that Chrome is very persistent with the caching of the source maps (at least, so it seems to me).
Whenever I start debugging, I use the Debug option of Visual Studio 2019. Which will then launch a new Chrome instance to do the debugging/testing in. I always assumed that this was done, to make sure you were using a 'fresh' version of the browser (e.g. with an empty cache, and the like). It turns out that this does not apply to the source maps of this browser instance...!
I found out that caching was the problem, because I had a window open in my 'regular' Chrome, which was also set to the local development environment. And I decided to see how the source maps where shown there, more to sort of amuse myself and less because I thought that would lead to anything. And in that browser, the correct source maps were & are shown.
So I went back to my (still open) development instance of Chrome. And in that, I already had disabled the cache in the devtools, both in the settings, and via the checkbox on the network tab. But still the source maps remained cached. So I emptied the browser cache via the regular settings of Chrome. But still the source maps remained cached. I changed the settings in Visual Studio to open an incognito version of Chrome for debugging. And even now, I still see the incorrect/old source maps there (while they show up just fine in the regular browser instance)...
Very weird all of this, but at least I can now start working/debugging again!
I am getting the following error when I am trying to run "gulp" in my vue.js project after I have added an image tag in my Home.vue component [ <img class="img-fluid" src="../images/logoWhite.png"> ] :
stream.js:74
throw er; // Unhandled stream error in pipe.
^
Error: ModuleParseError: Module parse failed: G:\Projects\Cakes\src\images\logoWhite.png Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type.
SyntaxError: Unexpected character '�' (1:0)
I read that this error might be caused by babel and how it is configured in webpack.config.js. After trying some solutions listed, I still haven't managed to get it work. I have also tried to create a '.babelrc' file with the presets conditions for babel, but still it didn't work.
This is how 'webpack.config.js' file looks like:
var webpack = require('webpack')
module.exports = {
entry: [
'./src/main.js'
],
output: {
path: "/dist/js",
publicPath: "/dist/",
filename: "app.js"
},
watch: true,
module: {
loaders: [
{
test: /\.js$/,
// excluding some local linked packages.
// for normal use cases only node_modules is needed.
exclude: /node_modules|vue\/src|vue-router\//,
loader: 'babel'
},
{
test: /\.scss$/,
loaders: ['style', 'css', 'sass']
},
{
test: /\.vue$/,
loader: 'vue'
}
]
},
babel: {
presets: ['es2015'],
plugins: ['transform-runtime']
},
resolve: {
modulesDirectories: ['node_modules']
}
}
In package.json, I have the following packages as my devDependencies for babel:
"babel-core": "^6.1.21",
"babel-loader": "^6.1.0",
"babel-plugin-transform-runtime": "^6.1.18",
"babel-preset-es2015": "^6.13.2",
"babel-runtime": "^6.3.13"
Thanks in advance guys!
I had the same problem and my solution was to use 'file-loader'
Install:
npm install --save-dev file-loader
Add the module rule to your webpack.config.js
{ test: /\.(png|jpg|gif)$/, loader: 'file-loader?name=./images/[name].[ext]' }
CSS file:
.content {
background-image: url('./images/background.jpg');
}
The template section of a .vue file is loaded using vue-html-loader, which will attempt to load local resources (such as image tag src values) using require(<resource>)(details).
The error above is due to the fact that you don't have a webpack loader setup to handle .png files, to fix it you'd need to install and configure a suitable loader - something like this, with url-loader, should work:
{ test: /\.png$/, loader: "url-loader?mimetype=image/png" }