I'm creating a PWA react application in which I configure the manifest.json file and serviceWroker.js file.
In the development mode, it works fine but when I create production build using webpack, manifest.json file does not load in the Build folder.
Does anyone know what's the issue?
Here is my webpack.config.js file
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const WebpackRTLPlugin = require('webpack-rtl-plugin');
const WebpackMessages = require('webpack-messages');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const del = require('del');
const webpack = require('webpack');
// theme name
const themeName = 'metronic';
// global variables
const rootPath = path.resolve(__dirname);
const distPath = rootPath + '/src';
const mainConfig = function() {
const isEnvDevelopment = false;
const isEnvProduction = true;
return {
mode: 'production',
stats: 'errors-only',
performance: {
hints: false
},
externals: [ 'jspdf', 'jspdf-autotable' ],
entry: './src/index.js',
output: {
// main output path in assets folder
path: path.resolve(__dirname, 'dist'),
// output path based on the entries' filename
// filename: '[name].js',
filename: isEnvProduction
? 'static/js/[name].[contenthash:8].js'
: isEnvDevelopment && 'static/js/bundle.js',
// TODO: remove this when upgrading to webpack 5
futureEmitAssets: true,
// There are also additional JS chunk files if you use code splitting.
chunkFilename: isEnvProduction
? 'static/js/[name].[contenthash:8].chunk.js'
: isEnvDevelopment && 'static/js/[name].chunk.js',
// We inferred the "public path" (such as / or /my-project) from homepage.
// We use "/" in development.
publicPath: '/artbot/app/'
},
resolve: { extensions: [ '.scss', '.css','.mjs','.jsx', '.js', '.json' ] },
optimization: {
minimize: true,
namedChunks: true,
nodeEnv: 'production',
removeAvailableModules: true,
removeEmptyChunks: true,
mergeDuplicateChunks: true,
minimizer: [ new OptimizeCssAssetsPlugin(), new TerserPlugin({ cache: true }) ],
splitChunks: {
chunks: "all"
}
},
plugins: [
// webpack log message
new WebpackMessages({
name: themeName,
logger: (str) => console.log(`>> ${str}`)
}),
new BundleAnalyzerPlugin(),
new webpack.optimize.AggressiveMergingPlugin(),
new HtmlWebpackPlugin({
title: 'Custom Template',
template: 'public/index.html',
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
}
}),
// create css file
new MiniCssExtractPlugin({
filename: 'static/css/[name].css'
}),
new WebpackRTLPlugin({
filename: 'static/css/[name].rtl.css',
minify: true
}),
{
apply: (compiler) => {
// hook name
compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
(async () => {
await del.sync(distPath + '/sass/*.js', { force: true });
})();
});
}
}
],
module: {
rules: [
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
// exclude: /#babel(?:\/|\\{1,2})runtime/,
exclude: /node_modules/,
loader: require.resolve('babel-loader'),
options: {
babelrc: true,
plugins: [
[
require.resolve('babel-plugin-named-asset-import'),
{
loaderMap: {
svg: {
ReactComponent: '#svgr/webpack?-svgo,+titleProp,+ref![path]'
}
}
}
]
]
}
},
{
test: /\.css$/,
loader: 'css-loader'
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'resolve-url-loader',
options: {
removeCR: true
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
},
{
test: /\.(png|jpg|svg)$/,
loader: 'file-loader',
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]',
esModule: false
}
//loader: 'url-loader?limit=8192'
},
{
test: /\.(woff2|eot|ttf|woff)$/,
loader: 'url-loader'
},
{
test: /\.json$/,
loader: 'file-loader',
type: 'javascript/auto',
exclude: /node_modules/,
options: {
name: 'static/json/[name].[hash:8].[ext]'
}
},
{
test: /\.html$/i,
loader: 'html-loader'
}
]
}
};
};
module.exports = function() {
return [ mainConfig() ];
};
Related
Im trying to use url-loader to convert file URLs into inline data URLs for my CSS backgrounds. When I run the build command, it generates the CSS & JS files without any error but the background image URLs remain unchanged in the CSS output.
Here's my webpack config:
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const ManifestPlugin = require('webpack-manifest-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = (env, argv) => ({
entry: {
app: ['./app/Resources/js/app.js', './app/Resources/scss/app.scss']
},
output: {
path: path.join(__dirname, "/web/build"),
filename: argv.mode === 'production' ? '[name].[hash].js' : '[name].js'
},
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: false // set to true if you want JS source maps
}),
new OptimizeCSSAssetsPlugin({
cssProcessorPluginOptions: {
preset: ['default', { discardComments: { removeAll: true } }],
},
})
]
},
devServer: {
contentBase: './web',
port: 9000,
disableHostCheck: true
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
},
resolve: {
extensions: ['.js']
}
},
{
test: /\.scss$/,
resolve: {
extensions: ['.scss']
},
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: "css-loader"
},
{
loader: "sass-loader",
options: {
sassOptions: {
outputStyle: 'expanded',
includePaths: ['./node_modules/foundation-sites/scss']
}
}
}
]
},
{
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
},
}
],
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: argv.mode === 'production' ? '[name].[contenthash].css' : '[name].css'
}),
new ManifestPlugin(),
new CleanWebpackPlugin()
],
});
My CSS is just a standard SCSS file:
.icon { background:url('path/to/icon.svg'); }
In the final output, I'd expect path/to/icon.svg to be replaced by a data URL. What am I doing wrong?
I decided to give webpack a shot and am using a starter kit for a small project. I'm not sure where I am going wrong but I want to add a new directory of files and access them like any other build.In this case it is the folder "particles.js-master". When I add a directory I cannot seem to access anything in the folder. I'm assuming I have to add an output or the like to the webpack config? Any advice would be greatly appreciated, thanks :)
here is my project structure
webpack:
const path = require('path');
const webpack = require('webpack');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const PreloadWebpackPlugin = require('preload-webpack-plugin');
const CssUrlRelativePlugin = require('css-url-relative-plugin');
const glob = require('glob');
const IS_DEV = process.env.NODE_ENV === 'dev';
const config = {
mode: IS_DEV ? 'development' : 'production',
devtool: IS_DEV ? 'eval' : 'source-map',
entry: './src/js/index.js',
output: {
filename: 'js/[name].[hash].js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
{
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: IS_DEV,
},
},
'css-loader',
'sass-loader',
],
},
{
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
name: '[name].[ext]',
fallback: 'file-loader',
outputPath: 'public/images',
},
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 65,
},
pngquant: {
quality: '65-90',
speed: 4,
},
gifsicle: {
interlaced: false,
},
webp: {
quality: 75,
},
},
},
],
},
],
},
plugins: [
new CleanWebpackPlugin(),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'windows.jQuery': 'jquery',
}),
new CopyWebpackPlugin([
{
from: './src/public',
to: 'public',
},
]),
new MiniCssExtractPlugin({
filename: IS_DEV ? 'css/[name].css' : 'css/[name].[contenthash].css',
chunkFilename: 'css/[id].css',
}),
new webpack.HashedModuleIdsPlugin(),
new PreloadWebpackPlugin({
include: 'initial',
}),
new CssUrlRelativePlugin(),
],
devServer: {
contentBase: path.join(__dirname, 'src'),
},
optimization: {
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /node_modules/,
chunks: 'initial',
name: 'vendor',
priority: 10,
enforce: true,
},
},
},
minimizer: [],
},
};
if (!IS_DEV) {
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
config.optimization.minimizer.push(
new TerserPlugin(),
new OptimizeCSSAssetsPlugin({})
);
}
const files = glob.sync('./src/*.html');
files.forEach(file => {
config.plugins.push(
new HtmlWebPackPlugin({
filename: path.basename(file),
template: file,
favicon: path.resolve(__dirname, './src/public/icon.ico'),
minify: !IS_DEV,
})
);
});
module.exports = config;
I have posted my Webpack configs below for a production environment. I am attempting to use background-image: url(../img/chevron-thin-right.svg); in one of my SCSS files but it is being resolved to background-image: url([object Module]) and therefore not working. I am trying to port a purely SCSS and HTML project into a react app being bundled by Webpack so this above approach used to work. Any fixes would be greatly appreciated.
webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const outputDirectory = 'dist';
module.exports = {
entry: './src/client/index.js',
output: {
path: path.join(__dirname, outputDirectory),
filename: 'bundle.js'
},
plugins: [
new HtmlWebpackPlugin({
title: 'Production',
template: './public/index.html',
favicon: './public/favicon.ico',
hash: true,
filename: 'index.html'
})
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.(jpg|png|woff|woff2|eot|ttf)$/,
use: {
loader: 'file-loader?limit=100000&name=images/[name].[ext]'
}
},
{
test: /\.svg$/,
use: [
"babel-loader",
{
loader: "react-svg-loader",
options: {
svgo: {
plugins: [
{
removeTitle: true,
removeComments: true
}
],
floatPrecision: 2
}
}
}
]
}
]
}
};
webpack.prod.js
const merge = require('webpack-merge');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const common = require('./webpack.common.js');
const path = require('path');
const autoprefixer = require('autoprefixer');
module.exports = {};
module.exports = merge(common, {
mode: 'production',
optimization: {
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true
}
}
}
},
plugins: [
new CleanWebpackPlugin(['dist']),
new MiniCssExtractPlugin({
filename: '[name].css'
})
],
module: {
rules: [
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true,
root: path.resolve(__dirname),
},
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
autoprefixer({
'browsers': ['last 2 versions', 'ie >= 10'],
}),
],
sourceMap: true,
},
},
{
loader: 'sass-loader',
options: {
outputStyle: 'compressed',
sourceMap: true,
includePaths: [
'./src/client/style/scss',
],
},
}
]
}
]
}
});
In case anybody else is looking for an answer I was able to solve it. It was due to not loading the associated SVG through the url-loader. Another problem arose when adding svg back in because my inline SVGs I wanted to use as React components were running into errors as they were now going through the url-loader instead of my react-svg-loader.
Below is the working webpack.common.js and webpack.prod.js stayed the same. The solution was to differentiate my inline and external SVGs by turning all inline extensions from .svg to .inline.svg and adjusting webpack config accordingly
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const outputDirectory = 'dist';
module.exports = {
entry: './src/client/index.js',
output: {
path: path.join(__dirname, outputDirectory),
filename: 'bundle.js'
},
plugins: [
new HtmlWebpackPlugin({
title: 'Production',
template: './public/index.html',
favicon: './public/favicon.ico',
hash: true,
filename: 'index.html'
})
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.(jpg|png|woff|woff2|eot|ttf|svg)$/,
exclude: /\.inline.svg$/,
use: {
loader: 'url-loader?limit=1000&name=images/[name].[ext]'
}
},
{
test: /\.inline.svg$/,
use: [
"babel-loader",
{
loader: "react-svg-loader",
options: {
svgo: {
plugins: [
{
removeTitle: true,
removeComments: true
}
],
floatPrecision: 2
}
}
}
]
}
]
}
};
I've recently tried to add proper code splitting for the first time to one of my projects.
It's worked, however I think it's worked a little TOO well!
When I run bundle-analyser, my dist folder contains a bunch of other bundles that contain snapshots and test files and I can't find any information that would explain why this is happening!
here is my webpack.config.base.js
const path = require('path');
const postcssNested = require('postcss-nested');
const postcssSimpleVars = require('postcss-simple-vars');
const postcssPresetEnv = require('postcss-preset-env');
const postcssImport = require('postcss-import');
const postcssFor = require('postcss-for');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractCssPluginConfig = new ExtractTextPlugin({
filename: '[name].[hash].css',
disable: false,
});
const HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
inject: 'body',
});
module.exports = {
entry: {
main: './src/index.jsx',
},
output: {
path: path.resolve('_dist'),
chunkFilename: '[name].[hash].bundle.min.js',
filename: '[name].[hash].min.js',
publicPath: '/',
},
module: {
rules: [
{
test: /\.(js|jsx)?$/,
loader: 'babel-loader',
exclude: /node_modules\/(?!(dom7|ssr-window|swiper)\/).*/,
},
{
test: /\.css$/,
loader: 'style-loader',
},
{
test: /\.css$/,
loader: 'css-loader',
query: {
modules: true,
importLoaders: 1,
localIdentName: '[path]___[name]__[local]___[hash:base64:5]',
},
},
{
test: /\.css$/,
loader: 'postcss-loader',
options: {
plugins: () => [
postcssNested,
postcssImport,
postcssFor,
postcssPresetEnv({
browsers: '>1%',
autoprefixer: {
grid: true,
browsers: ['>1%'],
},
insertBefore: {
'all-property': postcssSimpleVars,
},
}),
],
},
},
{
test: /\.(png|jp(e*)g|svg)$/,
use: [{
loader: 'url-loader',
options: {
limit: 8000,
name: 'images/[hash]-[name].[ext]',
},
}],
},
{
test: /\.(woff|woff2|ttf|eot|otf)$/,
use: 'file-loader?name=fonts/[name].[ext]',
},
{
test: /\.(pdf)$/,
use: [{
loader: 'url-loader',
options: { limit: 8000, name: 'documents/[hash]-[name].[ext]' },
}],
},
],
},
resolve: {
extensions: ['.js', '.jsx', '.css', '.svg'],
modules: [path.resolve('./node_modules')],
alias: {
Pages: path.resolve(__dirname, 'src/pages/'),
Sections: path.resolve(__dirname, 'src/sections/'),
Components: path.resolve(__dirname, 'src/components/'),
Images: path.resolve(__dirname, 'src/images/'),
Downloads: path.resolve(__dirname, 'src/downloads/'),
Services: path.resolve(__dirname, 'src/services/'),
Enum: path.resolve(__dirname, 'src/enum/'),
Data: path.resolve(__dirname, 'src/data/'),
Utils: path.resolve(__dirname, 'src/utils/'),
Config: path.resolve(__dirname, 'src/config/'),
},
},
plugins: [
ExtractCssPluginConfig,
HtmlWebpackPluginConfig,
],
};
and here is my webpack.config.build.js
const webpack = require('webpack');
const merge = require('webpack-merge');
const WebpackCleanupPlugin = require('webpack-cleanup-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const baseConfig = require('./webpack.config.base');
const WebpackCleanupPluginConfig = new WebpackCleanupPlugin({
exclude: ['webpack.stats.json'],
quiet: true,
});
const CopyWebpackPluginConfig = new CopyWebpackPlugin([
{ from: './src/documents', to: './documents' },
]);
module.exports = () => {
const DefinePluginConfig = new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production'),
});
return (
merge(baseConfig, {
optimization: {
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'initial',
enforce: true,
},
},
},
noEmitOnErrors: true,
concatenateModules: true,
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: false,
}),
],
},
plugins: [
DefinePluginConfig,
WebpackCleanupPluginConfig,
CopyWebpackPluginConfig,
],
})
);
};
I've tried adding a regex that matches any files with .test.js/jsx and .snap to my module.rules object but that did nothing.
Any help would be greatly appreciated!
If your test files are in a different directory, you might want to consider adding exclude property within the modules rules for js files.
Refer the following document: https://webpack.js.org/configuration/module/?_sm_au_=iVVKrMW7ZsbHQPbq#rule-exclude
or the following example: https://webpack.js.org/configuration/?_sm_au_=iVVKrMW7ZsbHQPbq#options
Another solution would be to use the IgnorePlugin. Docs for IgnorePlugin here: https://webpack.js.org/plugins/ignore-plugin/?_sm_au_=iVVKrMW7ZsbHQPbq
I can't figure out how to access JSON data in my pug templates.
Here is my pug layout
title #{htmlWebpackPlugin.pages[page].title}
Pug page which is initializing page variable
block vars
- var page = "catalog"
Webpack part
new HtmlWebpackPlugin({
filename: 'catalog.html',
chunks: ['main'],
template: PATHS.source + '/views/pages/catalog.pug',
inject: true,
data: {
pages: require('./dev/util/options.json')
}
})
JSON
"pages": {
"catalog": {
"title": "Catalog",
"description": "",
"keywords": ""
}
}
Each page is a separate pug and json.
First, I declare the entry, in my case it is a separate js file entry.js
module.exports.html = {
'index': 'index',
'about': 'o-mnie',
'contact': 'kontakt'
};
Webpack part
Include entry:
const entry = require('./entry.js');
Next add entry to HtmlWebpackPlugin:
const entryHtmlPlugins = Object.keys(entry.html).map(entryName => {
return new HtmlWebpackPlugin({
filename: `${entry.html[entryName]}.html`,
template: `./source/templates/containers/${entryName}/${entryName}.pug`,
chunks: [entryName],
file: require(`../source/templates/containers/${entryName}/${entryName}.json`)
})
});
See the full code how to use json data from pug and webpack -> github
const webpack = require("webpack");
const path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const SimpleProgressWebpackPlugin = require('simple-progress-webpack-plugin');
const entry = require('./entry.js');
const entryHtmlPlugins = Object.keys(entry.html).map(entryName => {
return new HtmlWebpackPlugin({
filename: `${entry.html[entryName]}.html`,
template: `./source/templates/containers/${entryName}/${entryName}.pug`,
path: path.join(__dirname, "../dist/"),
chunks: [entryName],
// inject: true,
// cache: true,
file: require(`../source/templates/containers/${entryName}/${entryName}.json`),
mode: 'development'
})
});
const output = {
path: path.resolve(__dirname, "source"),
filename: "[name].[hash].js",
publicPath: "/"
}
const config = {
devtool: "eval-source-map",
mode: "development",
entry: entry.site,
output: output,
module: {
rules: [
{
// JS
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
}
},
{
// CSS | SCSS
test: /\.(css|scss)$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [{
loader: 'css-loader'
},
{
loader: 'postcss-loader',
options: {
plugins: () => [require('autoprefixer')({
'browsers': ['> 1%', 'last 2 versions']
})],
}
},
{
loader: 'sass-loader'
},
{
loader: 'sass-resources-loader', // style-resources-loader then we can use sass, less, stylus
options: {
resources: [
path.resolve(__dirname, '../source/scss/main.scss')
]
},
}
]
})
},
{
// IMAGES
test: /\.(jpe?g|png|gif|svg)$/i,
loader: "file-loader"
},
{
// PUG
test: /\.pug$/,
loader: 'pug-loader',
options: {
pretty: true,
self: true
}
}
],
},
plugins: [
new SimpleProgressWebpackPlugin({
format: 'compact'
}),
new ExtractTextPlugin({
filename: '[name].[hash].css',
// disable: false,
allChunks: true
}),
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(false)
}),
].concat(entryHtmlPlugins)
};
module.exports = config;