React.JS:TypeError:无法读取 findLoader 处未定义的属性“过滤器”

IT技术 reactjs
2021-05-03 21:27:06

我正在学习使用 react.JS 制作 yelp 克隆的教程(https://www.fullstackreact.com/articles/react-tutorial-cloning-yelp/#routing)。我不断遇到错误:

类型错误:无法在 findLoader 处读取未定义的属性“过滤器”

该错误发生在我的 webpack.config.js 文件中,并且不允许我运行该程序或建立到我的本地主机的连接。

const NODE_ENV = process.env.NODE_ENV || 'development';
const dotenv = require('dotenv');

const webpack = require('webpack');
const path = require('path');

const join = path.join;
const resolve = path.resolve;

const getConfig = require('hjs-webpack');

const isDev = NODE_ENV === 'development';
const isTest = NODE_ENV === 'test';

// devServer config
const devHost   = process.env.HOST || 'localhost';
const devPort   = process.env.PORT || 3000;

const setPublicPath = process.env.SET_PUBLIC_PATH !== 'false';
const publicPath  = (isDev && setPublicPath) ? `//${devHost}:${devPort}/` : '';

const root = resolve(__dirname);
const src = join(root, 'src');
const modules = join(root, 'node_modules');
const dest = join(root, 'dist');
const css = join(src, 'styles');

var config = getConfig({
  isDev: isDev || isTest,
  in: join(src, 'app.js'),
  out: dest,
  html: function (context) {
    return {
      'index.html': context.defaultTemplate({
        title: 'FoodFinder',
        publicPath,
        meta: {}
      })
    };
  }
});

// ENV variables
const dotEnvVars = dotenv.config();
const environmentEnv = dotenv.config({
  path: join(root, 'config', `${NODE_ENV}.config.js`),
  silent: true
});
const envVariables =
    Object.assign({}, dotEnvVars, environmentEnv);

const defines =
  Object.keys(envVariables)
  .reduce((memo, key) => {
    const val = JSON.stringify(envVariables[key]);
    memo[`__${key.toUpperCase()}__`] = val;
    return memo;
  }, {
    __NODE_ENV__: JSON.stringify(NODE_ENV),
    __DEBUG__: isDev
  });

config.plugins = [
  new webpack.DefinePlugin(defines)
].concat(config.plugins);
// END ENV variables

// CSS modules
const cssModulesNames = `${isDev ? '[path][name]__[local]__' : ''}[hash:base64:5]`;

const matchCssLoaders = /(^|!)(css-loader)($|!)/;

const findLoader = (loaders, match) => {
  const found = loaders.filter(l => l && l.loader && l.loader.match(match));
  return found ? found[0] : null;
};

// existing css loader
const cssloader =
  findLoader(config.module.loaders, matchCssLoaders);

const newloader = Object.assign({}, cssloader, {
  test: /\.module\.css$/,
  include: [src],
  loader: cssloader.loader.replace(matchCssLoaders, `$1$2?modules&localIdentName=${cssModulesNames}$3`)
});
config.module.loaders.push(newloader);
cssloader.test = new RegExp(`[^module]${cssloader.test.source}`);
cssloader.loader = newloader.loader;

config.module.loaders.push({
  test: /\.css$/,
  include: [modules],
  loader: 'style!css'
});

// CSS modules

// postcss
config.postcss = [].concat([
  require('precss')({}),
  require('autoprefixer')({}),
  require('cssnano')({})
]);

// END postcss

// Roots
config.resolve.root = [src, modules];
config.resolve.alias = {
  css: join(src, 'styles'),
  containers: join(src, 'containers'),
  components: join(src, 'components'),
  utils: join(src, 'utils'),
  styles: join(src, 'styles')
};
// end Roots

// Dev
if (isDev) {
  config.devServer.port = devPort;
  config.devServer.hostname = devHost;
}

// Testing
if (isTest) {
  config.externals = {
    'react/addons': true,
    'react/lib/ReactContext': true,
    'react/lib/ExecutionEnvironment': true
  };

  config.module.noParse = /[/\\]sinon\.js/;
  config.resolve.alias.sinon = 'sinon/pkg/sinon';

  config.plugins = config.plugins.filter(p => {
    const name = p.constructor.toString();
    const fnName = name.match(/^function (.*)\((.*\))/);

    const idx = [
      'DedupePlugin',
      'UglifyJsPlugin'
    ].indexOf(fnName[1]);
    return idx < 0;
  });
}
// End Testing

    module.exports = config;

我对 React.JS 和全栈开发很陌生,所以任何帮助将不胜感激。

2个回答

@Tyler Sebastian 提供的答案将不起作用,因为const cssloader = findLoader(...);用于根据您正在使用的教程查找现有的 cssloader,而正在推送的新 loader 将替换它。

根据对教程的评论,错误似乎是教程中使用的技术已更新,导致它中断。评论者建议的解决方案是删除您的 node_modules 目录,用教程存储库中提供的文件替换 webpack.config.js 文件并重新安装依赖项(本质上是恢复到旧版本的技术)。

我不认为这是一个好的方法,因为目的是学习一些有用的东西,不仅让它起作用,而且它应该起作用。由于我是一个同样缺乏经验的 React 开发人员,他试图使用这个过时的教程,我想不出更好的解决方案

编辑:我已经尝试了评论建议的解决方案,但它不起作用。

一个可能的原因是你在“注册”加载器之前寻找加载器

const cssloader = findLoader(config.module.loaders, matchCssLoaders);

出现在 的使用之前config.module.loaders.push(...)很难说,因为您是config通过函数调用进行初始化的,所以我不确定初始值是什么。

如果您预计config.modules要成为的类型null | loader[],则可以将第一行更改findLoaderconst found = (loaders || []).filter(...)

还,

const findLoader = (loaders, match) => {
  const found = loaders.filter(l => l && l.loader && l.loader.match(match));
  return found ? found[0] : null;
};

不会做你认为会......考虑

let x = [] // an empty array
console.log(x ? "not empty" : "empty")

> "not empty"

它不像 Python3 那样空数组 == False 并且filter总是返回一个数组