Skip to content

Instantly share code, notes, and snippets.

@petrosmm
Created September 30, 2023 18:41
Show Gist options
  • Save petrosmm/9573d59dd5699bc9adefc14eab37b352 to your computer and use it in GitHub Desktop.
Save petrosmm/9573d59dd5699bc9adefc14eab37b352 to your computer and use it in GitHub Desktop.
working but slightly messy next.config.js with bundle splitting for webpack5 / nextjs 13
/**
* @typedef {import("next").NextConfig} NextConfig
* @typedef {import("webpack").Configuration} WebpackConfig
* @typedef {import("next/dist/server/config-shared").WebpackConfigContext} WebpackConfigContext
* @typedef {(config: WebpackConfig, context: WebpackConfigContext) => any} NextWebpackConfig
* @typedef {import("webpack").optimize.SplitChunksPlugin} SplitChunksPlugin
* @typedef {import("@next/bundle-analyzer")} BundleAnalyzerPlugin
* @typedef {import("copy-webpack-plugin")} CopyPlugin
* https://nextjs.org/docs/api-reference/next.config.js/custom-webpack-config
* https://adamjberkowitz.com/blog/post/managing-webpack-vendor-chunks-and-wordpress
* https://github.com/vercel/next.js/discussions/35969#discussioncomment-2523019
* https://medium.com/faceyspacey/how-to-use-webpacks-new-magic-comment-feature-with-react-universal-component-ssr-a38fd3e296a
*/
// const path = require("path")
// const buildPath = process.env !== "production" ? path.resolve(__dirname, "dev-build") : path.resolve(__dirname, "build");
// const TerserPlugin = require("terser-webpack-plugin");
const plugins = [];
const isAnalyze = process.env.ANALYZE === "true";
const webpack = require("webpack");
const pageExtensions = ["page.tsx", "page.ts", "page.jsx", "page.js", "api.ts", "api.js", /* just incase */ "api.tsx"];
const CopyPlugin = require("copy-webpack-plugin");
/** @type CopyPlugin */
const copyPlugin = new CopyPlugin({
patterns: [
{
from: './server-resources',
to: './server-resources',
},
{
from: './server-resources',
to: './server-resources',
},
],
});
// bundle analyzer here
if (isAnalyze) {
// only load dependency if env `ANALYZE` was set
/** @type BundleAnalyzerPlugin */
const withBundleAnalyzer = require("@next/bundle-analyzer")({
enabled: true,
});
plugins.push(withBundleAnalyzer)
}
/** @type {Omit<NextConfig, 'webpack'>} nextConfig */
const nextConfig = {
// https://nextjs.org/docs/pages/api-reference/next-config-js/output
distDir: "out",
reactStrictMode: true,
// keep this compression off it's gzip based: https://nextjs.org/docs/pages/api-reference/next-config-js/compress
compress: false,
pageExtensions: pageExtensions,
poweredByHeader: false,
swcMinify: true,
/** @type {NextWebpackConfig} */
webpack(config, context) {
let isDev = context.dev;
let isServer = context.isServer;
// https://stackoverflow.com/questions/64926174/module-not-found-cant-resolve-fs-in-next-js-application
if (false) if (!isServer && true) { config.resolve.fallback = { fs: false }; }
if (false)
config.resolve.fallback = {
"fs": false,
"path": false,
"os": false,
};
// NOTE: jQuery added via
// https://dev.to/anuraggharat/adding-bootstrap-to-nextjs-39b2
if (!isDev) {
// https://medium.com/@abhayshiravanthe/modules-and-code-splitting-in-webpack-5-6ce0a58d7f36
config.optimization.splitChunks = {};
config.optimization.splitChunks.automaticNameDelimiter = "_";
config.optimization.splitChunks.minSize = 17000;
config.optimization.splitChunks.minRemainingSize = 0;
config.optimization.splitChunks.minChunks = 1;
config.optimization.splitChunks.maxAsyncRequests = 30;
config.optimization.splitChunks.maxInitialRequests = 30;
config.optimization.splitChunks.automaticNameDelimiter = "_";
config.optimization.splitChunks.enforceSizeThreshold = 30000;
config.optimization.splitChunks.cacheGroups = {
common: {
test: /[\\/]node_modules[\\/]/,
priority: -5,
reuseExistingChunk: true,
chunks: "initial",
name: "common_app",
minSize: 0,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
// we are opting out of defaultVendors, so rest of the node modules will be part of default cacheGroup
defaultVendors: false,
bootstrap: {
test: /[\\/]node_modules[\\/](bootstrap)[\\/]/,
name: 'vendor_bootstrap',
chunks: "all",
priority: 9,
},
reactPackage: {
test: /[\\/]node_modules[\\/](react|react-dom|react-router|react-router-dom|react-usestateref|react-query)[\\/]/,
name: 'vendor_react',
chunks: "all",
priority: 10,
},
// not sure which popper picks up
jqueryAndPopper: {
test: /[\\/]node_modules[\\/](jquery|popper|@popperjs|popperjs|popper.js)[\\/]/,
name: 'vendor_jqueryandpopper',
chunks: "all",
priority: 11,
},
moment: {
test: /[\\/]node_modules[\\/](moment)[\\/]/,
name: 'vendor_moment',
chunks: "all",
priority: 12,
},
linq: {
test: /[\\/]node_modules[\\/](linq)[\\/]/,
name: 'vendor_linq',
chunks: "all",
priority: 13,
},
mui_material: {
test: /[\\/]node_modules[\\/](@mui)[\\/](material|icons-material|base|system)[\\/]/,
name: 'vendor_muimaterial',
chunks: "all",
priority: 14,
},
mui_material_date: {
test: /[\\/]node_modules[\\/](@mui)[\\/](x-date-pickers)[\\/]/,
name: 'vendor_muimaterial_date',
chunks: "all",
priority: 15,
},
misc: {
test: /[\\/]node_modules[\\/](html-minifier|html-react-parser|react-obfuscate-email|string-strip-html|mime-types)[\\/]/,
name: 'vendor_misc',
chunks: "all",
priority: 16,
},
// serverside chunk only
directus: {
test: /[\\/]node_modules[\\/](@directus)[\\/](sdk)[\\/]/,
name: 'vendor_directus',
chunks: "all",
priority: 17,
},
chrono_node: {
test: /[\\/]node_modules[\\/](chrono-node)[\\/]/,
name: 'vendor_chrono-node',
chunks: "all",
priority: 18,
},
emotion: {
test: /[\\/]node_modules[\\/](@emotion)[\\/](styled|react)[\\/]/,
name: 'vendor_emotion',
chunks: "all",
priority: 19,
},
// TODO does not do anything remove me later, please
deprecated: {
test: /[\\/]node_modules[\\/](graphql-tag|material-ui-popup-state)[\\/]/,
name: 'vendor_deprecated',
chunks: "all",
priority: 20,
},
};
}
config.plugins.push(copyPlugin);
if (false)
console.log(`config.plugins`, config.plugins);
config.optimization.minimize = !isDev;
config.optimization.chunkIds = "deterministic";
config.optimization.moduleIds = "deterministic";
if (false) {
this.rewrites = async () => {
// let z = await fetch("https://reqres.in/api/users?page=2");
// let zz = await z.json();
if (false) {
// console.log(zz);
console.log("hello from rewrites");
}
return {
// After checking all Next.js pages (including dynamic routes)
// and static files we proxy any other requests
fallback: [
{
source: "/:path*",
destination: `https://www.website.org/:path*`,
},
],
}
};
}
return config;
},
staticPageGenerationTimeout: 2400,
experimental: {
// largePageDataBytes: 128 * 100000,
isrMemoryCacheSize: 150,
},
// https://nextjs.org/docs/pages/api-reference/next-config-js/rewrites
rewrites: undefined,
}
module.exports = () => plugins.reduce((acc, next) => next(acc), nextConfig);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment