在将我的作品集从类组件迁移到使用hooks的函数组件时,我在生产构建中遇到了一些之前没有出现过的错误。所有的组件都是函数组件(除了错误边界),它们使用useState或useEffect,但似乎其中任何一个的存在都会导致此错误:
错误未发生在我的开发环境中,我已添加了react-hooks eslint插件,它应该可以捕获任何这些不变式违规。是否还有其他人在使用React 16.7.0-alpha时遇到了类似的生产问题?我做错了什么吗?
引起错误的其中一个组件:"不变式冲突:缩小后的React错误#298;Hooks只能在函数组件的主体内调用。"
import React, { useState, memo } from 'react';
import { NavLink } from 'react-router-dom';
import { NavBrand, Nav } from './styles';
import Hamburger from './Hamburger';
import { Links, Link } from './styles';
function NavBar() {
const [open, handleMenu] = useState(false);
return (
<Nav>
<NavBrand onClick={() => handleMenu(false)}>
<NavLink to="/">
<i className="icon-brand" />
</NavLink>
</NavBrand>
<Hamburger open={open} onClick={() => handleMenu(!open)} />
<Links open={open} role="menu">
<Link
onClick={() => handleMenu(false)}
to="/"
exact
>
Home <i className="icon-home" />
</Link>
<Link
onClick={() => handleMenu(false)}
to="/portfolio"
>
Portfolio <i className="icon-briefcase" />
</Link>
<Link
onClick={() => handleMenu(false)}
to="/contact"
>
Contact <i className="icon-message-square" />
</Link>
</Links>
</Nav>
);
};
export default memo(NavBar);
Webpack.config.js
module.exports = function(env, argv) {
const isProd = argv.mode === 'production';
const plugins = [
new webpack.DefinePlugin({
NODE_ENV: JSON.stringify(argv.mode),
GA_ID: JSON.stringify(process.env.GA_ID)
}),
new WebpackBar({ name: 'portfolio', color: '#269bda' })
];
if (isProd) {
plugins.push(
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html'
}),
new CopyWebpackPlugin(['netlify', 'pwa', 'static']),
new ManifestPlugin({
fileName: 'asset-manifest.json'
}),
new CompressionPlugin({
asset: '[path].gz[query]',
algorithm: 'gzip',
test: /\.js$|\.css$/,
minRatio: 0.9,
deleteOriginalAssets: false
}),
new SWPrecacheWebpackPlugin({
// By default, a cache-busting query parameter is appended to requests
// used to populate the caches, to ensure the responses are fresh.
// If a URL is already hashed by Webpack, then there is no concern
// about it being stale, and the cache-busting can be skipped.
dontCacheBustUrlsMatching: /\.\w{8}\./,
filename: 'service-worker.js',
// staticFileGlobs: ['/vendor.bundle.js'],
logger(message) {
if (message.indexOf('Total precache size is') === 0) {
// This message occurs for every build and is a bit too noisy.
return;
}
console.log(message);
},
// minify and uglify the script
minify: true,
// For unknown URLs, fallback to the index page
navigateFallback: '/index.html',
// Don't precache sourcemaps, build asset manifest,
// netlify redirects, or app js.
staticFileGlobsIgnorePatterns: [
/\.map$/,
/manifest.json$/,
/_redirects$/,
/js.bundle.js$/,
/[0-9].bundle.js$/
]
}),
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
}),
new webpack.optimize.AggressiveMergingPlugin(),
new MiniCssExtractPlugin({
filename: 'styles.css',
chunkFilename: '[id].css'
})
);
} else {
plugins.push(
new webpack.HotModuleReplacementPlugin(),
new BrowserSyncPlugin(
// BrowserSync options
{
host: 'localhost',
port: 8080,
open: false,
// proxy the Webpack Dev Server endpoint
// (which should be serving on http://localhost:8080/)
// through BrowserSync
proxy: 'http://localhost:8080/',
logPrefix: 'Portfolio'
},
// prevent BrowserSync from reloading the page
// and let Webpack Dev Server take care of this
{
reload: true
}
),
new CaseSensitivePathsPlugin(),
new FriendlyErrorsWebpackPlugin(),
new SystemBellPlugin(),
new DuplicatePackageCheckerPlugin(),
new StyleLintPlugin({
files: './app/assets/scss/*.scss'
})
);
}
return {
devtool: isProd ? 'hidden-source-map' : 'cheap-module-source-map',
context: sourcePath,
entry: {
js: [
// react-error-overlay
!isProd && 'react-dev-utils/webpackHotDevClient',
// fetch polyfill
isProd && 'whatwg-fetch',
// app entry
'app.tsx'
].filter(Boolean)
},
output: {
path: publicPath,
filename: '[name].bundle.js',
devtoolModuleFilenameTemplate: isProd
? info => path.relative(sourcePath, info.absoluteResourcePath).replace(/\\/g, '/')
: info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')
},
module: {
rules: [
{
test: /\.html$/,
exclude: /node_modules/,
use: {
loader: 'html-loader'
}
},
{
test: /\.js$/,
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: false
}
},
{
test: /\.json$/,
loader: 'json-loader',
type: 'javascript/auto'
},
{
test: /\.(scss|css)$/,
use: [
isProd && {
loader: MiniCssExtractPlugin.loader
},
!isProd && {
loader: 'style-loader',
options: {
sourceMap: false
}
},
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
].filter(Boolean)
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader'
}
]
},
{
test: /\.(ts|tsx)?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{ enforce: 'pre', test: /\.js$/, loader: 'source-map-loader' },
{
test: /\.(ttf|eot|svg|woff|woff2)(\?[a-z0-9]+)?$/,
loader: 'file-loader'
},
{
test: /\.(png|jpg)$/,
exclude: /node_modules/,
use: ['file-loader']
}
]
},
resolve: {
extensions: [
'.webpack-loader.js',
'.web-loader.js',
'.loader.js',
'.jsx',
'.tsx',
'.js',
'.ts'
],
modules: [path.resolve(__dirname, 'node_modules'), sourcePath]
},
plugins,
// split out vendor js into its own bundle
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'initial'
}
}
}
},
performance: isProd && {
maxAssetSize: 600000,
maxEntrypointSize: 600000,
hints: 'warning'
},
stats: {
colors: {
green: '\u001b[32m'
}
},
devServer: {
contentBase: './src',
historyApiFallback: true,
port: 8080,
compress: isProd,
inline: !isProd,
hot: false,
quiet: true,
before: function(app) {
// This lets us open files from the runtime error overlay.
app.use(errorOverlayMiddleware());
}
}
};
};
错误未发生在我的开发环境中,我已添加了react-hooks eslint插件,它应该可以捕获任何这些不变式违规。是否还有其他人在使用React 16.7.0-alpha时遇到了类似的生产问题?我做错了什么吗?
useRef()
定义了一个未使用的const
时。当我删除这行代码后,生产环境构建成功了。看起来webpack对于这个未使用的变量进行了一些“聪明”的优化。 - Arthur Andersen