当我在我的项目中将 webpack 包更新到 V5.x 时,我遇到了问题。这是错误:webpack-hot-client:entry
对象值必须是数组或函数。请检查您的 webpack 配置。
这是我的 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" } }```
这是我的 webpack 的 base.config.js :
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 }
我尝试了很多东西并修复了很多问题,但对我来说,条目是一个数组,所以我不知道为什么会出现这个错误。
这是我的 server.js(他启动所有程序):
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'))
}
}
)
更新:我在编译器文件中放了一些 console.log :
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 返回:
main: { import: [ 'webpack-hot-middleware/client', './src/index.js' ] }
}
{ import: [ 'webpack-hot-middleware/client', './src/index.js' ] }
true
所以我认为变量的声明有问题,因为我们必须做一个 Object.values() 来获取数组。所以我可以做些什么来解决这个问题,我不会更改依赖文件......谢谢你的时间和你的回应!
问候