I have a problem when i updated in my project the webpack package to V5.x.
Here is the error :
webpack-hot-client: entry Object values must be an Array or Function. Please check your webpack config.
Here is my package.json :
"*.css", "*.scss", "*.sass" ], "main": "index.js", "scripts": { "analyze": "bnr clean:build && bnr analyze", "build:all": "bnr clean:build && bnr build:client && bnr build:server", "build:client": "bnr clean:build && bnr build:client", "build:server": "bnr clean:build && bnr build:server", "clean": "bnr clean:build", "dev": "bnr dev", "docker": "yarn docker:build && yarn docker:start && yarn docker:status", "docker:build": "docker-compose build --no-cache", "docker:start": "docker-compose up -d", "docker:status": "docker-compose logs -f -t", "flow": "bnr flow", "flow:stop": "bnr flow:stop", "lint": "npm-run-all lint:js lint:style lint:json", "lint:js": "bnr lint:js", "lint:style": "bnr lint:style", "lint:json": "bnr lint:json", "prod": "bnr build:client && bnr build:server && bnr start", "start": "bnr start", "sitemap": "node sitemap-generator.js" }, "betterScripts": { "analyze": { "command": "npx webpack -p --progress --hide-modules --config ./tools/webpack/production.client.babel.js", "env": { "NODE_ENV": "analyze" } }, "build:client": { "command": "npx webpack --hide-modules --config ./tools/webpack/production.client.babel.js && npx gulp --gulpfile tools/gulpfile.js", "env": { "NODE_ENV": "production" } }, "build:server": { "command": "npx babel ./src -d ./dist --copy-files && npx webpack --hide-modules --config ./tools/webpack/production.server.babel.js", "env": { "NODE_ENV": "production" } }, "clean:build": { "command": "rimraf ./public/assets && rimraf ./public/webpack-assets.json" }, "dev": { "command": "nodemon ./index.js", "env": { "NODE_PATH": "./src", "NODE_ENV": "development", "PORT": 3000 } }, "flow": { "command": "npx flow" }, "flow:stop": { "command": "npx flow stop" }, "lint:js": { "command": "npx eslint --fix ./src ./tools ./index.js" }, "lint:json": { "command": "npx prettier --write src/**/**/*.json" }, "lint:style": { "command": "npx stylelint --fix ./src/**/*.css, ./src/**/*.scss" }, "start": { "command": "node ./index.js", "env": { "NODE_PATH": "./dist", "NODE_HOST": "0.0.0.0", "NODE_ENV": "production", "PORT": 8080 } } }, "husky": { "hooks": { "pre-commit": "lint-staged" } }, "lint-staged": { "*.{js,jsx}": "eslint --fix", "*.{json,md}": "prettier --write", "*.{scss,sass}": "stylelint --syntax=scss" }, "nodemonConfig": { "watch": [ "src/server.js", "src/handler.js", "src/utils/renderHtml.js", "src/theme/variables.scss" ] }, "browserslist": [ "> 1%", "last 3 versions" ], "eslintIgnore": [ "tools/flow", "public/assets" ], "dependencies": { "@babel/cli": "^7.14.5", "@babel/plugin-proposal-export-namespace-from": "^7.5.2", "@fortawesome/fontawesome-free": "^5.15.1", "@hapi/address": "^4.1.0", "@koa/router": "^10.1.1", "@loadable/component": "^5.10.2", "@loadable/server": "^5.10.2", "@tweenjs/tween.js": "^18.3.1", "ansi-regex": "^6.0.1", "axios": "^0.23.0", "bootstrap": "^5.1.3", "chalk": "^4.1.2", "classnames": "^2.2.6", "d3-ease": "^3.0.1", "del": "^6.0.0", "esm": "^3.2.25", "glob-parent": "^6.0.2", "gulp": "^4.0.2", "gulp-cache": "^1.1.3", "gulp-imagemin": "^8.0.0", "gulp-postcss": "^9.0.0", "gulp-rename": "^2.0.0", "i18next": "^21.3.2", "i18next-browser-languagedetector": "^6.1.2", "i18next-node-fs-backend": "^2.1.3", "i18next-resource-store-loader": "^0.1.2", "i18next-xhr-backend": "^3.1.2", "imagemin-mozjpeg": "^9.0.0", "imagemin-pngquant": "^9.0.2", "koa": "^2.8.1", "koa-bodyparser": "^4.2.1", "koa-compress": "^5.1.0", "koa-favicon": "^2.0.1", "koa-helmet": "^6.1.0", "koa-i18next-detector": "^0.7.2", "koa-i18next-middleware": "^1.1.12", "koa-i18next-middleware-fixed": "^1.1.10-b3", "koa-morgan": "^1.0.1", "koa-mount": "^4.0.0", "koa-router": "^10.1.1", "koa-static": "^5.0.0", "koa-webpack": "^6.0.0", "koa-webpack-server": "^0.2.4", "micro-dash": "^8.1.0", "moment": "^2.24.0", "p-min-delay": "^4.0.1", "pm2": "^5.1.2", "qs": "^6.8.0", "rc-animate": "^3.1.1", "rc-queue-anim": "^2.0.0", "rc-scroll-anim": "^2.6.1", "rc-tween-one": "^2.6.3", "react": "^17.0.2", "react-bootstrap": "^1.0.0-beta.8", "react-dom": "npm:@hot-loader/react-dom@^16.8.6", "react-global-configuration": "^1.4.1", "react-gtm-module": "^2.0.11", "react-helmet": "^6.1.0", "react-i18next": "^11.12.0", "react-icons": "^4.3.1", "react-motion": "^0.5.2", "react-player": "^2.9.0", "react-pose": "^4.0.8", "react-router": "^5.0.1", "react-router-config": "^5.0.1", "react-router-dom": "^5.0.1", "react-router-last-location": "^2.0.1", "react-router-sitemap": "^1.2.0", "react-spring": "^9.3.0", "react-tilt": "^0.1.4", "react-typist": "^2.0.5", "react-youtube": "^7.9.0", "sass-resources-loader": "^2.0.1", "serialize-javascript": "^6.0.0", "styled-components": "^5.3.1", "terser-webpack-plugin": "^5.2.4" }, "devDependencies": { "@babel/core": "^7.6.0", "@babel/node": "^7.14.5", "@babel/plugin-proposal-class-properties": "^7.5.5", "@babel/plugin-proposal-export-default-from": "^7.5.2", "@babel/plugin-proposal-optional-chaining": "^7.6.0", "@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/preset-env": "^7.14.5", "@babel/preset-flow": "^7.0.0", "@babel/preset-react": "^7.14.5", "@babel/register": "^7.6.0", "@babel/runtime": "^7.6.0", "@loadable/babel-plugin": "^5.10.0", "@loadable/webpack-plugin": "^5.7.1", "asset-require-hook": "^1.2.0", "babel-eslint": "^10.0.3", "babel-loader": "^8.0.6", "babel-plugin-dynamic-import-node": "^2.3.0", "babel-plugin-istanbul": "^6.1.1", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", "babel-plugin-transform-remove-console": "^6.9.4", "better-npm-run": "^0.1.1", "compression-webpack-plugin": "^9.0.0", "core-js": "3", "css-loader": "^6.4.0", "css-modules-require-hook": "^4.2.3", "cssnano": "^5.0.8", "eslint": "^8.0.1", "eslint-config-airbnb": "^18.0.1", "eslint-config-prettier": "^8.3.0", "eslint-import-resolver-webpack": "^0.13.1", "eslint-plugin-flowtype": "^6.1.1", "eslint-plugin-import": "^2.18.2", "eslint-plugin-jsx-a11y": "^6.2.3", "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-react": "^7.14.3", "eslint-plugin-react-hooks": "^4.2.0", "file-loader": "^6.2.0", "flow-bin": "^0.162.0", "friendly-errors-webpack-plugin": "^1.7.0", "html-minifier": "^4.0.0", "husky": "^7.0.2", "imagemin-webpack-plugin": "^2.4.2", "lint-staged": "^11.2.3", "mini-css-extract-plugin": "^2.4.2", "nodemon": "^2.0.13", "normalize.css": "^8.0.1", "npm-run-all": "^4.1.5", "optimize-css-assets-webpack-plugin": "^6.0.1", "postcss": "^8.3.9", "postcss-loader": "^6.2.0", "postcss-preset-env": "^6.7.0", "prettier": "^2.4.1", "react-dev-utils": "^11.0.4", "react-hot-loader": "^4.12.13", "react-router-sitemap-generator": "^0.0.8", "react-test-renderer": "^17.0.2", "rimraf": "^3.0.0", "sass": "^1.43.2", "sass-loader": "^12.2.0", "static-site-generator-webpack-plugin": "^3.4.2", "stylelint": "^13.13.1", "stylelint-config-prettier": "^9.0.3", "stylelint-config-recommended-scss": "^4.3.0", "stylelint-config-standard": "^22.0.0", "stylelint-scss": "^3.10.1", "url-loader": "^4.1.1", "webpack": "^5.58.2", "webpack-bundle-analyzer": "^4.5.0", "webpack-cli": "4.9.1", "webpack-dev-middleware": "^5.2.1", "webpack-hot-middleware": "^2.25.0", "webpack-manifest-plugin": "^4.0.2", "webpack-merge": "^5.8.0", "webpack-node-externals": "^3.0.0" }, "engines": { "node": ">=8", "npm": ">=5" } }```
Here is my base.config.js of webpack :
import webpack from 'webpack'
import { WebpackManifestPlugin } from 'webpack-manifest-plugin'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin'
import LoadablePlugin from '@loadable/webpack-plugin'
import config from './config'
const nodeEnv = process.env.NODE_ENV || 'development'
const isDev = nodeEnv === 'development'
const getPlugins = () => {
const plugins = [
new WebpackManifestPlugin({
fileName: path.resolve(process.cwd(), 'public/webpack-assets.json'),
filter: file => file.isInitial
}),
new MiniCssExtractPlugin({
filename: `${config.cssFileName}.css`,
chunkFilename: `${config.cssChunkFileName}.css`,
ignoreOrder: true
}),
// Setup environment variables for client
new webpack.EnvironmentPlugin({ NODE_ENV: JSON.stringify(nodeEnv) }),
// Setup global variables for client
new webpack.DefinePlugin({
__CLIENT__: true,
__SERVER__: false,
__DEV__: isDev
}),
new LoadablePlugin({ filename: '../loadable-stats.json', writeToDisk: true })
]
if (isDev) {
plugins.push(new FriendlyErrorsWebpackPlugin())
}
return plugins
}
// Webpack configuration
module.exports = {
mode: isDev ? 'development' : 'production',
devtool: isDev ? 'eval-source-map' : 'hidden-source-map',
context: path.resolve(process.cwd()),
entry: ['webpack-hot-middleware/client','./src/index.js'],
optimization: {
splitChunks: {
chunks: 'async'
}
},
output: {
path: path.resolve(process.cwd(), 'public/assets'),
publicPath: '/assets/',
filename: `${config.fileName}.js`,
chunkFilename: `${config.chunkFileName}.js`,
pathinfo: isDev
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel',
options: { cacheDirectory: isDev }
},
{
test: /\.css$/,
include: /node_modules/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css',
options: {
importLoaders: 1,
modules: false,
sourceMap: true
}
},
{ loader: 'postcss', options: { sourceMap: true } }
]
},
{
test: /\.(scss|sass)$/,
exclude: path.resolve(__dirname, '..', '..', 'src/theme/'),
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: isDev,
reloadAll: true
}
},
{
loader: 'css',
options: {
importLoaders: 2,
modules: {
localIdentName: config.cssModulesIdentifier,
context: path.resolve(process.cwd(), 'src')
},
sourceMap: true
}
},
{ loader: 'postcss', options: { sourceMap: true } },
{
loader: 'sass',
options: {
sassOptions: {
outputStyle: 'expanded'
},
sourceMap: true
}
},
{
loader: 'sass-resources',
options: {
resources: path.resolve(process.cwd(), 'src/theme/_include.scss')
}
}
]
},
{
test: /\.(scss|sass)$/,
include: path.resolve(__dirname, '..', '..', 'src/theme/'),
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: isDev,
reloadAll: true
}
},
{
loader: 'css',
options: {
importLoaders: 2,
modules: false,
sourceMap: true
}
},
{ loader: 'postcss', options: { sourceMap: true } },
{
loader: 'sass',
options: {
sassOptions: {
outputStyle: 'expanded'
},
sourceMap: true
}
}
]
},
{
test: path.resolve(process.cwd(), 'src/locales'),
loader: 'i18next-resource-store-loader'
},
{
test: /\.(woff2?|ttf|eot|svg|otf)$/,
loader: 'url',
options: { limit: 10240, name: config.staticFilesName }
},
{
test: /\.(gif|png|jpe?g|webp)$/,
// Any image below or equal to 10Kb will be converted to base64
loader: 'url',
options: { limit: 10240, name: config.staticFilesName }
},
{
test: /\.(mp3|mp4|ogv)$/,
loader: 'file',
options: { name: config.staticFilesName }
}
]
},
plugins: getPlugins(),
resolveLoader: {
mainFields: ['loader']
},
resolve: {
modules: ['src', 'node_modules'],
descriptionFiles: ['package.json'],
extensions: ['.js', '.jsx', '.json'],
fallback:{
fs: false,
vm: false,
net: false,
tls: false
}
},
cache: isDev,
stats: { children: false }
I tried a lot of things and i fixed a lot of issues but for me the entry is an Array, so i don't know why i got this error.
Here there is my server.js (he launches all the programs) :
import logger from 'koa-morgan'
import Koa from 'koa'
import bodyParser from 'koa-bodyparser'
import compression from 'koa-compress'
import helmet from 'koa-helmet'
import querystring from 'qs'
import Router from '@koa/router'
import favicon from 'koa-favicon'
import axios from 'axios'
import chalk from 'chalk'
import mount from 'koa-mount'
import serve from 'koa-static'
import Backend from 'i18next-node-fs-backend'
import i18n from 'i18next'
import i18nextMiddleware from 'koa-i18next-middleware-fixed'
import LanguageDetector from 'koa-i18next-detector'
import c from './config'
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0
const app = new Koa()
const router = new Router()
const sendMessage = body =>
new Promise((resolve, reject) => {
const config = {
maxRedirects: 0,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
axios
.post(
'https://go.pardot.com/l/138941/2019-07-22/2h6dgb',
querystring.stringify({ ...body, privacy: true }),
config
)
.then(result => {
resolve(result.status === 200)
})
.catch(e => {
reject(new Error(e))
})
})
const lngDetector = new LanguageDetector()
i18n
.use(Backend)
.use(lngDetector)
.init(
{
debug: false,
fallbackLng: 'fr',
saveMissing: false,
react: {
useSuspense: false
},
detection: {
order: ['path', 'navigator']
},
interpolation: {
escapeValue: false,
formatSeparator: ',',
format: (value, format) => {
if (format === 'uppercase') return value.toUpperCase()
return value
}
},
preload: ['fr'],
load: 'languageOnly',
ns: [
'global',
'landing_references',
'landing_expertises',
'home',
'references',
'expertises',
'contact',
'about',
'partners',
'team'
],
defaultNS: 'global',
backend: {
loadPath: `${path.resolve(process.cwd(), 'src')}/locales/{{lng}}/{{ns}}.json`
}
},
async () => {
// Use helmet to secure Express with various HTTP headers
app.use(helmet())
app.use(bodyParser())
// Compress all requests
app.use(compression())
// Use for http request debug (show errors only)
app.use(logger('dev', { skip: ctx => ctx.status < 400 }))
app.use(favicon(path.resolve(process.cwd(), 'public/favicon.ico')))
app.use(i18nextMiddleware.getHandler(i18n, { locals: 'lng' }))
// Docker serve static trough nginx for better performance
if (!__DOCKER__) {
console.log(chalk.magenta('==> Serve statics with koa'))
app.use(mount('/locales', serve(path.resolve(process.cwd(), 'src/locales'))))
app.use(serve(path.resolve(process.cwd(), 'public')))
}
if (__DEV__) {
app.use(mount('/images', serve(path.resolve(process.cwd(), 'src/images'))))
/* Run express as webpack dev server */
const webpack = require('webpack')
const webpackConfig = require('../tools/webpack/base.config')
const compiler = webpack(webpackConfig)
const koaWebpack = require('koa-webpack')
new webpack.ProgressPlugin().apply(compiler)
const options = {
compiler,
devMiddleware: {
publicPath: webpackConfig.output.publicPath,
headers: { 'Access-Control-Allow-Origin': '*' },
hot: true,
writeToDisk: false,
quiet: true, // Turn it on for friendly-errors-webpack-plugin
noInfo: true,
stats: 'minimal',
serverSideRender: true
}
}
const middleware = await koaWebpack(options)
app.use(middleware)
}
router
.post('/contact', async ctx => {
try {
await sendMessage(ctx.request.body)
ctx.body = {
message: 'Votre message a bien été envoyé'
}
ctx.status = 200
} catch (e) {
ctx.body = {
message: 'Une erreur est survenue'
}
ctx.status = 500
}
})
.get('/', async ctx => {
ctx.status = 302
return ctx.redirect(`/${ctx.request.language}`)
})
.get('*', async (ctx, next) => {
return require('./render')(ctx, next)
})
app.use(router.routes()).use(router.allowedMethods())
if (c.port) {
app.listen(c.port, c.host, err => {
const url = `http://${c.host}:${c.port}`
if (err) console.error(chalk.red(`\n==> Error happen ${err}`))
console.info(chalk.green(`\n==> Listening at ${url}`))
})
} else {
console.error(chalk.red('\n==> Error : No PORT environment variable has been specified'))
}
}
)
UPDATE : I put some console.log in the compiler file :
for (const key of Object.keys(entry)) {
const value = entry[key];
console.log(entry)
console.log(value)
console.log(Array.isArray(Object.values(value)))
if (!Array.isArray(value)) {
throw new TypeError(
'webpack-hot-client: `entry` Object values must be an Array or Function. Please check your webpack config.'
);
Console.log return this :
main: { import: [ 'webpack-hot-middleware/client', './src/index.js' ] }
}
{ import: [ 'webpack-hot-middleware/client', './src/index.js' ] }
true
So i think that there is a problem with the declaration of variable, because we have to do an Object.values() to get the array. So idk what can i do to resolve the problem, i will not change the dependencies files... Thx for your time and your response!
Regards
It might not be the right example to your situation, but they made some internal changes to the webpack structure:
here's one of the newer examples I found:
Source: Webpack v5 internal changes: Entry