diff --git a/packages/documentation-framework/app.js b/packages/documentation-framework/app.js
index 58bb924916..bf7285a132 100644
--- a/packages/documentation-framework/app.js
+++ b/packages/documentation-framework/app.js
@@ -1,5 +1,5 @@
import React from 'react';
-import ReactDOM from 'react-dom';
+import { createRoot, hydrateRoot } from 'react-dom/client';
import { Router, useLocation } from '@reach/router';
import 'client-styles'; // Webpack replaces this import: patternfly-docs.css.js
import { SideNavLayout } from '@patternfly/documentation-framework/layouts';
@@ -107,8 +107,12 @@ const isPrerender = process.env.PRERENDER;
// Don't use ReactDOM in SSR
if (!isPrerender) {
function render() {
- const renderFn = isProd ? ReactDOM.hydrate : ReactDOM.render;
- renderFn(, document.getElementById('root'));
+ const container = document.getElementById('root');
+ if (isProd) {
+ hydrateRoot(container, );
+ } else {
+ createRoot(container).render();
+ }
}
// On first load, await promise for the current page to avoid flashing a "Loading..." state
const Component = getAsyncComponent(null);
diff --git a/packages/documentation-framework/package.json b/packages/documentation-framework/package.json
index 0b22bc015d..108eebee8c 100644
--- a/packages/documentation-framework/package.json
+++ b/packages/documentation-framework/package.json
@@ -22,19 +22,19 @@
"@babel/preset-env": "7.18.2",
"@mdx-js/util": "1.6.16",
"@patternfly/ast-helpers": "^0.4.57",
- "@reach/router": "1.3.4",
+ "@reach/router": "npm:@gatsbyjs/reach-router@1.3.9",
"autoprefixer": "9.8.6",
- "babel-loader": "8.2.5",
+ "babel-loader": "9.1.2",
"camelcase-css": "2.0.1",
"chokidar": "3.5.3",
- "clean-webpack-plugin": "3.0.0",
+ "clean-webpack-plugin": "4.0.0",
"codesandbox": "2.2.0",
"commander": "4.1.1",
- "copy-webpack-plugin": "6.1.0",
- "css-loader": "4.3.0",
+ "copy-webpack-plugin": "11.0.0",
+ "css-loader": "6.7.3",
"detab": "2.0.3",
"express": "4.18.1",
- "file-loader": "6.1.0",
+ "file-loader": "6.2.0",
"file-saver": "1.3.8",
"fs-extra": "9.0.1",
"glob": "8.0.3",
@@ -42,29 +42,30 @@
"hast-to-hyperscript": "9.0.0",
"hast-util-to-text": "2.0.0",
"html-formatter": "0.1.9",
- "html-webpack-plugin": "4.4.1",
+ "html-webpack-plugin": "5.5.0",
"js-yaml": "3.14.0",
"mdast-util-to-hast": "9.1.1",
"mdurl": "1.0.1",
- "mini-css-extract-plugin": "1.3.9",
- "monaco-editor": "0.21.3",
- "monaco-editor-webpack-plugin": "2.1.0",
- "null-loader": "4.0.0",
+ "mini-css-extract-plugin": "2.7.5",
+ "monaco-editor": "0.34.1",
+ "monaco-editor-webpack-plugin": "7.0.1",
"parse-entities": "2.0.0",
+ "path-browserify": "1.0.1",
"postcss": "7.0.32",
- "postcss-loader": "4.2.0",
+ "postcss-loader": "7.1.0",
+ "process": "^0.11.10",
"puppeteer": "14.3.0",
"puppeteer-cluster": "0.23.0",
"react-docgen": "5.3.1",
- "react-monaco-editor": "0.48.0",
- "react-ssr-prepass": "1.2.1",
+ "react-monaco-editor": "^0.51.0",
+ "react-ssr-prepass": "1.5.0",
"remark-footnotes": "1.0.0",
"remark-frontmatter": "2.0.0",
"remark-mdx": "2.0.0-next.8",
"remark-mdxjs": "2.0.0-next.8",
"remark-parse": "8.0.3",
"remark-squeeze-paragraphs": "4.0.0",
- "responsive-loader": "2.1.1",
+ "responsive-loader": "3.1.2",
"sharp": "0.30.6",
"style-to-object": "0.3.0",
"to-vfile": "6.1.0",
@@ -74,10 +75,10 @@
"unist-util-visit": "2.0.3",
"url-loader": "4.1.0",
"vfile-reporter": "6.0.1",
- "webpack": "4.44.1",
- "webpack-bundle-analyzer": "3.8.0",
- "webpack-cli": "3.3.12",
- "webpack-dev-server": "3.11.0",
+ "webpack": "5.76.3",
+ "webpack-bundle-analyzer": "4.8.0",
+ "webpack-cli": "5.0.1",
+ "webpack-dev-server": "4.13.1",
"webpack-merge": "5.8.0"
},
"peerDependencies": {
diff --git a/packages/documentation-framework/scripts/cli/start.js b/packages/documentation-framework/scripts/cli/start.js
index 4b89272cc9..988f8908c7 100644
--- a/packages/documentation-framework/scripts/cli/start.js
+++ b/packages/documentation-framework/scripts/cli/start.js
@@ -6,17 +6,15 @@ const { getConfig } = require('./helpers');
const { watchMD } = require('../md/parseMD');
function startWebpackDevServer(webpackConfig) {
- webpackConfig.devServer.filename = webpackConfig.output.filename;
- webpackConfig.devServer.publicPath = webpackConfig.output.publicPath;
+ webpackConfig.devServer.static.publicPath = webpackConfig.output.publicPath;
const { port } = webpackConfig.devServer;
const compiler = webpack(webpackConfig);
- const server = new WebpackDevServer(compiler, webpackConfig.devServer);
+ const server = new WebpackDevServer(webpackConfig.devServer, compiler);
- server.listen(port, 'localhost', err => {
- if (err) {
- console.log(err);
- }
- });
+ (async () => {
+ await server.start();
+ console.log(`Dev server is listening on port ${port}`);
+ })();
}
async function start(options) {
diff --git a/packages/documentation-framework/scripts/webpack/webpack.base.config.js b/packages/documentation-framework/scripts/webpack/webpack.base.config.js
index 1ede2f1a39..44c927961b 100644
--- a/packages/documentation-framework/scripts/webpack/webpack.base.config.js
+++ b/packages/documentation-framework/scripts/webpack/webpack.base.config.js
@@ -27,7 +27,8 @@ module.exports = (_env, argv) => {
output: {
publicPath: isProd ? `${pathPrefix}/` : '/',
pathinfo: false, // https://webpack.js.org/guides/build-performance/#output-without-path-info,
- hashDigestLength: 8
+ hashDigestLength: 8,
+ clean: true, // Clean the output directory before emit.
},
amd: false, // We don't use any AMD modules, helps performance
mode: isProd ? 'production' : 'development',
@@ -82,35 +83,28 @@ module.exports = (_env, argv) => {
},
{
test: /\.(gif|svg)$/,
- use: {
- loader: 'file-loader',
- options: {
- name: '[name].[contenthash].[ext]',
- outputPath: 'images/'
- },
+ type: 'asset/resource',
+ dependency: { not: ['url'] },
+ generator: {
+ filename: 'images/[hash][ext][query]'
}
},
{
test: /\.(pdf)$/,
- use: {
- loader: 'file-loader',
- options: {
- name: '[name].[contenthash].[ext]',
- }
+ type: 'asset/resource',
+ dependency: { not: ['url'] },
+ generator: {
+ filename: '[hash][ext][query]'
}
},
{
test: /.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
- use: [
- {
- loader: 'file-loader',
- options: {
- name: '[name].[ext]',
- outputPath: 'fonts/'
- }
- }
- ]
- }
+ type: 'asset/resource',
+ dependency: { not: ['url'] },
+ generator: {
+ filename: 'fonts/[name][ext][query]'
+ }
+ },
]
},
resolve: {
@@ -118,18 +112,25 @@ module.exports = (_env, argv) => {
alias: {
'client-styles': path.resolve(process.cwd(), 'patternfly-docs/patternfly-docs.css.js'),
'./routes-client': path.resolve(process.cwd(), 'patternfly-docs/patternfly-docs.routes.js'),
- './routes-generated': path.resolve(process.cwd(), 'patternfly-docs/generated/index.js')
+ './routes-generated': path.resolve(process.cwd(), 'patternfly-docs/generated/index.js'),
+ process: "process/browser"
},
modules: [
'node_modules',
...module.paths,
- ]
+ ],
+ fallback: {
+ "path": require.resolve("path-browserify")
+ },
},
// Use this module's node_modules first (for use in Core/React workspaces)
resolveLoader: {
modules: module.paths,
},
plugins: [
+ new webpack.ProvidePlugin({
+ process: 'process/browser',
+ }),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(mode),
'process.env.pathPrefix': JSON.stringify(isProd ? pathPrefix : ''),
@@ -150,13 +151,9 @@ module.exports = (_env, argv) => {
{ from: path.join(__dirname, '../../assets'), to: 'assets' }
]
}),
- new MonacoWebpackPlugin(),
- ...(isProd
- ? [
- new CleanWebpackPlugin()
- ]
- : []
- )
+ new MonacoWebpackPlugin({
+ globalAPI: true,
+ })
],
stats: 'minimal'
};
diff --git a/packages/documentation-framework/scripts/webpack/webpack.client.config.js b/packages/documentation-framework/scripts/webpack/webpack.client.config.js
index 4600d90017..28537feb5d 100644
--- a/packages/documentation-framework/scripts/webpack/webpack.client.config.js
+++ b/packages/documentation-framework/scripts/webpack/webpack.client.config.js
@@ -5,6 +5,7 @@ const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPl
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
+const webpack = require('webpack');
const baseConfig = require('./webpack.base.config');
const { getHtmlWebpackPlugins } = require('./getHtmlWebpackPlugins');
@@ -23,18 +24,20 @@ const reactJSRegex = /react-([^\\/]*)[\\/]dist[\\/].*\.js$/
const clientConfig = async (env, argv) => {
const isProd = argv.mode === 'production';
-
return {
output: {
path: argv.output ? path.resolve(argv.output) : path.resolve('public'),
- filename: '[name].[hash].bundle.js'
+ filename: '[name].[contenthash].bundle.js'
},
devServer: {
hot: true,
historyApiFallback: true,
+ compress: true,
port: argv.port,
- clientLogLevel: 'info',
- stats: 'minimal'
+ client: {
+ logging: 'info',
+ },
+ static: {}
},
optimization: {
splitChunks: {
@@ -71,10 +74,7 @@ const clientConfig = async (env, argv) => {
},
minimize: isProd ? true : false,
minimizer: [
- new TerserPlugin({
- cache: path.join(process.cwd(), '.cache/terser'),
- ...(process.env.CI ? { parallel: 2 } : {})
- }),
+ new TerserPlugin(),
],
runtimeChunk: 'single',
},
@@ -82,7 +82,6 @@ const clientConfig = async (env, argv) => {
rules: [
{
test: /\.css$/,
- exclude: reactCSSRegex,
use: [
{
loader: MiniCssExtractPlugin.loader,
@@ -106,13 +105,12 @@ const clientConfig = async (env, argv) => {
}
]
},
- {
- test: reactCSSRegex,
- use: 'null-loader'
- },
]
},
plugins: [
+ new webpack.DefinePlugin({
+ 'process.env.PRERENDER': false,
+ }),
new MiniCssExtractPlugin(!isProd ? {} : {
filename: '[name].[contenthash].css',
chunkFilename: '[name].[contenthash].css',
diff --git a/packages/documentation-framework/scripts/webpack/webpack.server.config.js b/packages/documentation-framework/scripts/webpack/webpack.server.config.js
index dd959d5792..036c592c4e 100644
--- a/packages/documentation-framework/scripts/webpack/webpack.server.config.js
+++ b/packages/documentation-framework/scripts/webpack/webpack.server.config.js
@@ -2,8 +2,11 @@ const path = require('path');
const webpack = require('webpack');
const { merge } = require('webpack-merge');
const baseConfig = require('./webpack.base.config');
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
+const reactCSSRegex = /(react-[\w-]+\/dist|react-styles\/css)\/.*\.css$/;
-const serverConfig = () => {
+const serverConfig = async (env, argv) => {
+ const isProd = argv.mode === 'production';
return {
output: {
path: path.resolve('.cache/ssr-build'), // Don't bloat `public` dir
@@ -25,13 +28,26 @@ const serverConfig = () => {
rules: [
{
test: /\.css$/,
- use: 'null-loader'
+ use: [
+ {
+ loader: 'css-loader'
+ },
+ {
+ loader: 'postcss-loader',
+ options: {
+ postcssOptions: {
+ plugins: [
+ require('autoprefixer')({
+ env: '>0.25%, not ie 11, not op_mini all',
+ flexbox: false,
+ grid: false
+ })
+ ]
+ }
+ }
+ }
+ ]
},
- // This does weird things to document
- {
- test: /(novnc-core|@novnc\/novnc)\/.*\.js/,
- use: 'null-loader'
- }
]
},
resolve: {
@@ -41,7 +57,7 @@ const serverConfig = () => {
// The maintainer will not allow his bundle to be required from a node context
// https://github.com/xtermjs/xterm.js/pull/3134
'xterm': '@patternfly/documentation-framework/helpers/xterm',
- 'xterm-addon-fit': '@patternfly/documentation-framework/helpers/xterm-addon-fit'
+ 'xterm-addon-fit': '@patternfly/documentation-framework/helpers/xterm-addon-fit',
},
},
// Load in prerender.js instead
@@ -49,7 +65,7 @@ const serverConfig = () => {
};
}
-module.exports = (env = {}, argv) => merge(
+module.exports = async (env = {}, argv) => merge(
baseConfig(env, argv),
- serverConfig(env, argv)
+ await serverConfig(env, argv)
);
diff --git a/packages/documentation-framework/templates/html.ejs b/packages/documentation-framework/templates/html.ejs
index df2bc487ed..51fef81070 100644
--- a/packages/documentation-framework/templates/html.ejs
+++ b/packages/documentation-framework/templates/html.ejs
@@ -16,9 +16,7 @@
<%= htmlWebpackPlugin.tags.headTags %>
-
- <%= prerendering %>
-
+ <%= prerendering %>
<%= htmlWebpackPlugin.tags.bodyTags %>
<% if (algolia) { %>