recently I cleaned up the webpack
configuration in a project in order to make it more maintainable, I did so by splitting the configuration in two files:
// webpack.config.js
const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const { merge } = require("webpack-merge");
const parts = require("./webpack.parts");
const commonConfig = merge([
{
target: "web",
stats: {
optimizationBailout: true,
},
entry: {
index: {
import: parts.rootResolverFn("src/index/main.js"),
dependOn: "vendors",
},
vendors: ["react", "react-dom", "prop-types"],
},
output: {
filename: "[name].[contenthash].js",
path: parts.rootResolverFn("dist/public"),
publicPath: "/",
clean: true,
},
resolve: parts.resolve(),
},
parts.plugins(),
parts.loadJs(),
parts.loadAssets(),
parts.loadCss(),
parts.bundleAnalyzer(),
]);
const developmentConfig = merge([
{
output: {
filename: "[name].bundle.js",
pathinfo: false,
},
devtool: "eval-source-map",
devServer: parts.devServer(),
plugins: [new ReactRefreshWebpackPlugin()],
},
]);
const productionConfig = merge([
{
optimization: {
splitChunks: { chunks: "all" },
runtimeChunk: { name: "runtime" },
usedExports: true,
sideEffects: true,
minimizer: [
`...`,
new CssMinimizerPlugin({
minimizerOptions: {
preset: [
"default",
{
discardComments: { removeAll: true },
},
],
},
}),
],
},
},
]);
module.exports = (env, { mode }) => {
switch (mode) {
case "production":
return merge(commonConfig, productionConfig);
case "development":
return merge(commonConfig, developmentConfig);
default:
throw new Error(`Trying to use unknown mode: ${mode}`);
}
};
And the other file:
// webpack.parts.js
const path = require("path");
const { spawnSync } = require("child_process");
const webpack = require("webpack");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CopyPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const pkg = require("./package.json");
const root = path.join(__dirname, "./");
const pathResolver = (base) => (toResolve) => path.resolve(base, toResolve);
const rootResolver = pathResolver(root);
const isProd = process.env.NODE_ENV === "production";
let commitHash;
if (!isProd) {
try {
const { stdout } = spawnSync("git", ["rev-parse", "--short", "HEAD"]);
console.log(`Current commit is: ${String(stdout)}`);
commitHash = String(stdout);
} catch (e) {
console.warn("Could not retrieve hash for this development environment, is this a valid git repository?");
}
}
const copyPluginPatterns = [
{
from: rootResolver("src/assets"),
to: rootResolver("dist/public/assets"),
},
{
from: rootResolver("node_modules/mxgraph/javascript"),
to: rootResolver("dist/public/mxgraph"),
},
{
from: rootResolver("src/config.js"),
to: rootResolver("dist/public/"),
},
];
exports.rootResolverFn = (path) => rootResolver(path);
exports.devServer = () => ({
port: 8282,
hot: true,
historyApiFallback: true,
open: true,
client: {
overlay: true,
},
});
exports.resolve = () => ({
alias: {
api: rootResolver("src"),
components: rootResolver("src/components"),
shared: rootResolver("src/shared"),
},
extensions: ["*", ".js", ".jsx", ".json", ".mjs", ".es"],
modules: [path.resolve(root), path.resolve(root, "src"), path.resolve(root, "node_modules")],
symlinks: false,
});
exports.loadAssets = () => ({
module: {
rules: [
{
test: /\.(png|jpe?g|gif)$/,
type: "asset/resource",
},
{
test: /\.(svg)$/,
type: "asset/inline",
},
],
},
});
exports.loadJs = () => ({
module: {
rules: [
{
test: /\.m?(js|jsx)$/,
exclude: /(node_modules)/,
use: {
loader: "babel-loader",
options: {
plugins: [!isProd && require.resolve("react-refresh/babel")].filter(Boolean),
},
},
},
],
},
});
exports.loadCss = () => ({
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
sourceMap: true,
url: false,
},
},
"fast-sass-loader",
"postcss-loader",
],
},
],
},
});
exports.plugins = () => {
return {
plugins: [
new MiniCssExtractPlugin({
ignoreOrder: true,
filename: "[name].[contenthash].css",
}),
new CopyPlugin({
patterns: copyPluginPatterns,
}),
new webpack.DefinePlugin({
ENV: JSON.stringify(process.env.NODE_ENV || "development"),
VERSION: JSON.stringify(pkg.version),
TEST_MODE: JSON.stringify(process.env.TEST_MODE),
COMMIT_SHA: process.env.COMMIT_SHA || commitHash,
}),
new HtmlWebpackPlugin({
title: "MyApp",
meta: {
charset: "utf-8",
viewport: "width=device-width, initial-scale=1",
},
template: rootResolver("src/index/index.html"),
hash: true,
chunks: ["index", "vendors"],
minify: {
collapseWhitespace: false,
},
}),
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/locale$/,
contextRegExp: /moment$/,
}),
],
};
};
exports.bundleAnalyzer = (options = {}) => ({
plugins: [
new BundleAnalyzerPlugin({
analyzerHost: "localhost",
analyzerPort: "2112",
...options,
}),
],
});
After applying these changes the icons
from @fluentui/font-icons-mdl2
stopped showing correctly as in the following picture:
I'm using the recommended approach in the
The curious thing for me is that by inspecting the Network
tab in DevTools I can see the calls to retrieve the fonts and they're successful
However, as you could see a couple of images above the glyphs are not show correctly.
Has someone experienced similar issues with @fluentui/font-icons-mdl2
and webpack
recently? Thanks in advance.
CodePudding user response:
Well, I was able to figure out the problem, the problematic lines were:
splitChunks: { chunks: "all" },
runtimeChunk: { name: "runtime" },
After removing those lines the icons started to show up again as expected. I'll close this but I have the task to figure out exactly why that happened, that being said, webpack
is a terrific tool but you should really take your time and read the documentation very carefully. Cheers